Skip to contentSkip to conversation

drm/radeon: Add init interrupt kfd->kgd interface

PATCH New Oded Gabbay 1 participant 9 messages Apr 21, 2015

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

PATCH 1/9 drm/radeon: Add init interrupt kfd->kgd interface

This patch adds a new interface function to the kfd->kgd interface. The function is kgd_init_interrupts() and its function is to initialize a pipe's interrupts.

The function currently enables the timestamp interrupt and the bad opcode interrupt.

---
 drivers/gpu/drm/amd/include/kgd_kfd_interface.h |  2 ++
 drivers/gpu/drm/radeon/cik_reg.h                |  2 ++
 drivers/gpu/drm/radeon/cikd.h                   |  1 +
 drivers/gpu/drm/radeon/radeon_kfd.c             | 21 ++++++++++++++++++++-
 4 files changed, 25 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/include/kgd_kfd_interface.h +2 -0
index dabd944..4ea21ae 100644
@@ -144,6 +144,8 @@ struct kfd2kgd_calls {
 	int (*init_pipeline)(struct kgd_dev *kgd, uint32_t pipe_id,
 				uint32_t hpd_size, uint64_t hpd_gpu_addr);
 
+	int (*init_interrupts)(struct kgd_dev *kgd, uint32_t pipe_id);
+
 	int (*hqd_load)(struct kgd_dev *kgd, void *mqd, uint32_t pipe_id,
 			uint32_t queue_id, uint32_t __user *wptr);
 
drivers/gpu/drm/radeon/cik_reg.h +2 -0
index f667347..0ec5d53 100644
@@ -149,6 +149,8 @@
 
 #define KFD_CIK_SDMA_QUEUE_OFFSET		0x200
 
+#define CPC_INT_CNTL					0xC2D0
+
 #define CP_HQD_IQ_RPTR					0xC970u
 #define AQL_ENABLE					(1U << 0)
 #define SDMA0_RLC0_RB_CNTL				0xD400u
drivers/gpu/drm/radeon/cikd.h +1 -0
index 0089d83..b33ba3b 100644
@@ -1335,6 +1335,7 @@
 #       define CNTX_EMPTY_INT_ENABLE                    (1 << 20)
 #       define PRIV_INSTR_INT_ENABLE                    (1 << 22)
 #       define PRIV_REG_INT_ENABLE                      (1 << 23)
+#       define OPCODE_ERROR_INT_ENABLE                  (1 << 24)
 #       define TIME_STAMP_INT_ENABLE                    (1 << 26)
 #       define CP_RINGID2_INT_ENABLE                    (1 << 29)
 #       define CP_RINGID1_INT_ENABLE                    (1 << 30)
drivers/gpu/drm/radeon/radeon_kfd.c +20 -1
index 3db2300..813a416 100644
@@ -66,7 +66,7 @@ static int kgd_set_pasid_vmid_mapping(struct kgd_dev *kgd, unsigned int pasid,
 
 static int kgd_init_pipeline(struct kgd_dev *kgd, uint32_t pipe_id,
 				uint32_t hpd_size, uint64_t hpd_gpu_addr);
-
+static int kgd_init_interrupts(struct kgd_dev *kgd, uint32_t pipe_id);
 static int kgd_hqd_load(struct kgd_dev *kgd, void *mqd, uint32_t pipe_id,
 			uint32_t queue_id, uint32_t __user *wptr);
 static int kgd_hqd_sdma_load(struct kgd_dev *kgd, void *mqd);
@@ -89,6 +89,7 @@ static const struct kfd2kgd_calls kfd2kgd = {
 	.program_sh_mem_settings = kgd_program_sh_mem_settings,
 	.set_pasid_vmid_mapping = kgd_set_pasid_vmid_mapping,
 	.init_pipeline = kgd_init_pipeline,
+	.init_interrupts = kgd_init_interrupts,
 	.hqd_load = kgd_hqd_load,
 	.hqd_sdma_load = kgd_hqd_sdma_load,
 	.hqd_is_occupied = kgd_hqd_is_occupied,
@@ -407,6 +408,24 @@ static int kgd_init_pipeline(struct kgd_dev *kgd, uint32_t pipe_id,
 	return 0;
 }
 
+static int kgd_init_interrupts(struct kgd_dev *kgd, uint32_t pipe_id)
+{
+	uint32_t mec;
+	uint32_t pipe;
+
+	mec = (pipe_id / CIK_PIPE_PER_MEC) + 1;
+	pipe = (pipe_id % CIK_PIPE_PER_MEC);
+
+	lock_srbm(kgd, mec, pipe, 0, 0);
+
+	write_register(kgd, CPC_INT_CNTL,
+			TIME_STAMP_INT_ENABLE | OPCODE_ERROR_INT_ENABLE);
+
+	unlock_srbm(kgd);
+
+	return 0;
+}
+
 static inline uint32_t get_sdma_base_addr(struct cik_sdma_rlc_registers *m)
 {
 	uint32_t retval;
Signature · 6 lines
1.9.1

_______________________________________________
dri-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/dri-devel
#1 lore raw

PATCH 2/9 drm/amdkfd: Add interrupt handling module

From: Andrew Lewycky <[email protected]>

This patch adds the interrupt handling module, kfd_interrupt.c, and its related members in different data structures to the amdkfd driver.

The amdkfd interrupt module maintains an internal interrupt ring per amdkfd device. The internal interrupt ring contains interrupts that needs further handling. The extra handling is deferred to a later time through a workqueue.

There's no acknowledgment for the interrupts we use. The hardware simply queues a new interrupt each time without waiting.

The fixed-size internal queue means that it's possible for us to lose interrupts because we have no back-pressure to the hardware.

However, only interrupts that are "wanted" by amdkfd, are copied into the amdkfd s/w interrupt ring, in order to minimize the chances for overflow of the ring.

---
 drivers/gpu/drm/amd/amdkfd/Makefile                |   1 +
 drivers/gpu/drm/amd/amdkfd/kfd_device.c            |  22 ++-
 .../gpu/drm/amd/amdkfd/kfd_device_queue_manager.c  |  15 ++
 drivers/gpu/drm/amd/amdkfd/kfd_interrupt.c         | 181 +++++++++++++++++++++
 drivers/gpu/drm/amd/amdkfd/kfd_priv.h              |  17 ++
 5 files changed, 235 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/amd/amdkfd/kfd_interrupt.c
drivers/gpu/drm/amd/amdkfd/Makefile +1 -0
index 0f49601..cd09c05 100644
@@ -12,5 +12,6 @@ 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
 
 obj-$(CONFIG_HSA_AMD)	+= amdkfd.o
drivers/gpu/drm/amd/amdkfd/kfd_device.c +21 -1
index ca7f2d3..13c30a0 100644
@@ -235,6 +235,13 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd,
 		goto kfd_topology_add_device_error;
 	}
 
+	if (kfd_interrupt_init(kfd)) {
+		dev_err(kfd_device,
+			"Error initializing interrupts for device (%x:%x)\n",
+			kfd->pdev->vendor, kfd->pdev->device);
+		goto kfd_interrupt_error;
+	}
+
 	if (!device_iommu_pasid_init(kfd)) {
 		dev_err(kfd_device,
 			"Error initializing iommuv2 for device (%x:%x)\n",
@@ -273,6 +280,8 @@ dqm_start_error:
 device_queue_manager_error:
 	amd_iommu_free_device(kfd->pdev);
 device_iommu_pasid_error:
+	kfd_interrupt_exit(kfd);
+kfd_interrupt_error:
 	kfd_topology_remove_device(kfd);
 kfd_topology_add_device_error:
 	kfd_gtt_sa_fini(kfd);
@@ -290,6 +299,7 @@ void kgd2kfd_device_exit(struct kfd_dev *kfd)
 	if (kfd->init_complete) {
 		device_queue_manager_uninit(kfd->dqm);
 		amd_iommu_free_device(kfd->pdev);
+		kfd_interrupt_exit(kfd);
 		kfd_topology_remove_device(kfd);
 		kfd_gtt_sa_fini(kfd);
 		kfd->kfd2kgd->free_gtt_mem(kfd->kgd, kfd->gtt_mem);
@@ -333,7 +343,17 @@ int kgd2kfd_resume(struct kfd_dev *kfd)
 /* This is called directly from KGD at ISR. */
 void kgd2kfd_interrupt(struct kfd_dev *kfd, const void *ih_ring_entry)
 {
-	/* Process interrupts / schedule work as necessary */
+	if (!kfd->init_complete)
+		return;
+
+	spin_lock(&kfd->interrupt_lock);
+
+	if (kfd->interrupts_active
+	    && interrupt_is_wanted(kfd, ih_ring_entry)
+	    && enqueue_ih_ring_entry(kfd, ih_ring_entry))
+		schedule_work(&kfd->interrupt_work);
+
+	spin_unlock(&kfd->interrupt_lock);
 }
 
 static int kfd_gtt_sa_init(struct kfd_dev *kfd, unsigned int buf_size,
drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +15 -0
index 69af73f..5c530e1 100644
@@ -522,6 +522,17 @@ int init_pipelines(struct device_queue_manager *dqm,
 	return 0;
 }
 
+static void init_interrupts(struct device_queue_manager *dqm)
+{
+	unsigned int i;
+
+	BUG_ON(dqm == NULL);
+
+	for (i = 0 ; i < get_pipes_num(dqm) ; i++)
+		dqm->dev->kfd2kgd->init_interrupts(dqm->dev->kgd,
+				i + get_first_pipe(dqm));
+}
+
 static int init_scheduler(struct device_queue_manager *dqm)
 {
 	int retval;
@@ -581,6 +592,7 @@ static void uninitialize_nocpsch(struct device_queue_manager *dqm)
 
 static int start_nocpsch(struct device_queue_manager *dqm)
 {
+	init_interrupts(dqm);
 	return 0;
 }
 
@@ -750,6 +762,9 @@ static int start_cpsch(struct device_queue_manager *dqm)
 
 	dqm->fence_addr = dqm->fence_mem->cpu_ptr;
 	dqm->fence_gpu_addr = dqm->fence_mem->gpu_addr;
+
+	init_interrupts(dqm);
+
 	list_for_each_entry(node, &dqm->queues, list)
 		if (node->qpd->pqm->process && dqm->dev)
 			kfd_bind_process_to_device(dqm->dev,
drivers/gpu/drm/amd/amdkfd/kfd_interrupt.c new file +181 -0

181 lines not on this page · raw message

drivers/gpu/drm/amd/amdkfd/kfd_priv.h +17 -0
index f21fcce..34c7662 100644
@@ -161,10 +161,23 @@ struct kfd_dev {
 	unsigned int gtt_sa_chunk_size;
 	unsigned int gtt_sa_num_of_chunks;
 
+	/* Interrupts */
+	void *interrupt_ring;
+	size_t interrupt_ring_size;
+	atomic_t interrupt_ring_rptr;
+	atomic_t interrupt_ring_wptr;
+	struct work_struct interrupt_work;
+	spinlock_t interrupt_lock;
+
 	/* QCM Device instance */
 	struct device_queue_manager *dqm;
 
 	bool init_complete;
+	/*
+	 * Interrupts of interest to KFD are copied
+	 * from the HW ring into a SW ring.
+	 */
+	bool interrupts_active;
 };
 
 /* KGD2KFD callbacks */
@@ -555,7 +568,11 @@ struct kfd_dev *kfd_device_by_pci_dev(const struct pci_dev *pdev);
 struct kfd_dev *kfd_topology_enum_kfd_devices(uint8_t idx);
 
 /* Interrupts */
+int kfd_interrupt_init(struct kfd_dev *dev);
+void kfd_interrupt_exit(struct kfd_dev *dev);
 void kgd2kfd_interrupt(struct kfd_dev *kfd, const void *ih_ring_entry);
+bool enqueue_ih_ring_entry(struct kfd_dev *kfd,	const void *ih_ring_entry);
+bool interrupt_is_wanted(struct kfd_dev *dev, const uint32_t *ih_ring_entry);
 
 /* Power Management */
 void kgd2kfd_suspend(struct kfd_dev *kfd);
Signature · 6 lines
1.9.1

_______________________________________________
dri-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/dri-devel
#2 lore raw

PATCH 3/9 drm/amdkfd: add events IOCTL set definitions

In reply to Oded Gabbay

From: Andrew Lewycky <[email protected]>

- AMDKFD_IOC_CREATE_EVENT:
Creates a new event of a specified type

- AMDKFD_IOC_DESTROY_EVENT:
Destroys an existing event

- AMDKFD_IOC_SET_EVENT:
Signal an existing event

- AMDKFD_IOC_RESET_EVENT:
Reset an existing event

- AMDKFD_IOC_WAIT_EVENTS:
Wait on event(s) until they are signaled

---
 drivers/gpu/drm/amd/amdkfd/kfd_chardev.c | 45 +++++++++++++++
 include/uapi/linux/kfd_ioctl.h           | 94 +++++++++++++++++++++++++++++++-
 2 files changed, 137 insertions(+), 2 deletions(-)
drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +45 -0
index 19a4fba..9933b2e 100644
@@ -514,6 +514,36 @@ static int kfd_ioctl_get_process_apertures(struct file *filp,
 	return 0;
 }
 
+static int kfd_ioctl_create_event(struct file *filp, struct kfd_process *p,
+					void *data)
+{
+	return -ENODEV;
+}
+
+static int kfd_ioctl_destroy_event(struct file *filp, struct kfd_process *p,
+					void *data)
+{
+	return -ENODEV;
+}
+
+static int kfd_ioctl_set_event(struct file *filp, struct kfd_process *p,
+				void *data)
+{
+	return -ENODEV;
+}
+
+static int kfd_ioctl_reset_event(struct file *filp, struct kfd_process *p,
+				void *data)
+{
+	return -ENODEV;
+}
+
+static int kfd_ioctl_wait_events(struct file *filp, struct kfd_process *p,
+				void *data)
+{
+	return -ENODEV;
+}
+
 #define AMDKFD_IOCTL_DEF(ioctl, _func, _flags) \
 	[_IOC_NR(ioctl)] = {.cmd = ioctl, .func = _func, .flags = _flags, .cmd_drv = 0, .name = #ioctl}
 
@@ -539,6 +569,21 @@ static const struct amdkfd_ioctl_desc amdkfd_ioctls[] = {
 
 	AMDKFD_IOCTL_DEF(AMDKFD_IOC_UPDATE_QUEUE,
 			kfd_ioctl_update_queue, 0),
+
+	AMDKFD_IOCTL_DEF(AMDKFD_IOC_CREATE_EVENT,
+			kfd_ioctl_create_event, 0),
+
+	AMDKFD_IOCTL_DEF(AMDKFD_IOC_DESTROY_EVENT,
+			kfd_ioctl_destroy_event, 0),
+
+	AMDKFD_IOCTL_DEF(AMDKFD_IOC_SET_EVENT,
+			kfd_ioctl_set_event, 0),
+
+	AMDKFD_IOCTL_DEF(AMDKFD_IOC_RESET_EVENT,
+			kfd_ioctl_reset_event, 0),
+
+	AMDKFD_IOCTL_DEF(AMDKFD_IOC_WAIT_EVENTS,
+			kfd_ioctl_wait_events, 0),
 };
 
 #define AMDKFD_CORE_IOCTL_COUNT	ARRAY_SIZE(amdkfd_ioctls)
include/uapi/linux/kfd_ioctl.h +92 -2

112 lines not on this page · raw message

Signature · 6 lines
1.9.1

_______________________________________________
dri-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/dri-devel
#3 lore raw

PATCH 4/9 drm/amdkfd: Add the events module

In reply to Oded Gabbay

From: Andrew Lewycky <[email protected]>

This patch adds the events module (kfd_events.c) and the interrupt handler module for Kaveri (cik_event_interrupt.c).

The patch updates the interrupt_is_wanted(), so that it now calls the interrupt isr function specific for the device that received the interrupt. That function (implemented in cik_event_interrupt.c) returns whether this interrupt is of interest to us or not.

The patch also updates the interrupt_wq(), so that it now calls the device's specific wq function, which checks the interrupt source and tries to signal relevant events.

There is a limitation of 256 events per process, in order for the search for SQ interrupts to be a direct lookup. In the future, this limitation will be lifted.

---
 drivers/gpu/drm/amd/amdkfd/Makefile              |   2 +-
 drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c |  57 ++
 drivers/gpu/drm/amd/amdkfd/cik_int.h             |  54 ++
 drivers/gpu/drm/amd/amdkfd/kfd_chardev.c         |  16 +-
 drivers/gpu/drm/amd/amdkfd/kfd_device.c          |   1 +
 drivers/gpu/drm/amd/amdkfd/kfd_events.c          | 775 +++++++++++++++++++++++
 drivers/gpu/drm/amd/amdkfd/kfd_events.h          |  76 +++
 drivers/gpu/drm/amd/amdkfd/kfd_interrupt.c       |  11 +-
 drivers/gpu/drm/amd/amdkfd/kfd_priv.h            |  48 ++
 drivers/gpu/drm/amd/amdkfd/kfd_process.c         |  24 +
 10 files changed, 1059 insertions(+), 5 deletions(-)
 create mode 100644 drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c
 create mode 100644 drivers/gpu/drm/amd/amdkfd/cik_int.h
 create mode 100644 drivers/gpu/drm/amd/amdkfd/kfd_events.c
 create mode 100644 drivers/gpu/drm/amd/amdkfd/kfd_events.h
drivers/gpu/drm/amd/amdkfd/Makefile +1 -1
index cd09c05..652d254 100644
@@ -12,6 +12,6 @@ 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_interrupt.o kfd_events.o cik_event_interrupt.o
 
 obj-$(CONFIG_HSA_AMD)	+= amdkfd.o
drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c new file +57 -0

57 lines not on this page · raw message

drivers/gpu/drm/amd/amdkfd/cik_int.h new file +54 -0

54 lines not on this page · raw message

drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +14 -2
index 9933b2e..d0630cc 100644
@@ -289,8 +289,10 @@ static int kfd_ioctl_create_queue(struct file *filep, struct kfd_process *p,
 
 	args->queue_id = queue_id;
 
+
 	/* Return gpu_id as doorbell offset for mmap usage */
-	args->doorbell_offset = args->gpu_id << PAGE_SHIFT;
+	args->doorbell_offset = (KFD_MMAP_DOORBELL_MASK | args->gpu_id);
+	args->doorbell_offset <<= PAGE_SHIFT;
 
 	mutex_unlock(&p->mutex);
 
@@ -684,5 +686,15 @@ static int kfd_mmap(struct file *filp, struct vm_area_struct *vma)
 	if (IS_ERR(process))
 		return PTR_ERR(process);
 
-	return kfd_doorbell_mmap(process, vma);
+	if ((vma->vm_pgoff & KFD_MMAP_DOORBELL_MASK) ==
+			KFD_MMAP_DOORBELL_MASK) {
+		vma->vm_pgoff = vma->vm_pgoff ^ KFD_MMAP_DOORBELL_MASK;
+		return kfd_doorbell_mmap(process, vma);
+	} else if ((vma->vm_pgoff & KFD_MMAP_EVENTS_MASK) ==
+			KFD_MMAP_EVENTS_MASK) {
+		vma->vm_pgoff = vma->vm_pgoff ^ KFD_MMAP_EVENTS_MASK;
+		return radeon_kfd_event_mmap(process, vma);
+	}
+
+	return -EFAULT;
 }
drivers/gpu/drm/amd/amdkfd/kfd_device.c +1 -0
index 13c30a0..4c03169 100644
@@ -34,6 +34,7 @@ static const struct kfd_device_info kaveri_device_info = {
 	.asic_family = CHIP_KAVERI,
 	.max_pasid_bits = 16,
 	.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_events.c new file +775 -0

775 lines not on this page · raw message

drivers/gpu/drm/amd/amdkfd/kfd_events.h new file +76 -0

76 lines not on this page · raw message

drivers/gpu/drm/amd/amdkfd/kfd_interrupt.c +9 -2
index 5383dd0..7f134aa 100644
@@ -172,10 +172,17 @@ static void interrupt_wq(struct work_struct *work)
 				sizeof(uint32_t))];
 
 	while (dequeue_ih_ring_entry(dev, ih_ring_entry))
-		;
+		dev->device_info->event_interrupt_class->interrupt_wq(dev,
+								ih_ring_entry);
 }
 
 bool interrupt_is_wanted(struct kfd_dev *dev, const uint32_t *ih_ring_entry)
 {
-	return false;
+	/* integer and bitwise OR so there is no boolean short-circuiting */
+	unsigned wanted = 0;
+
+	wanted |= dev->device_info->event_interrupt_class->interrupt_isr(dev,
+								ih_ring_entry);
+
+	return wanted != 0;
 }
drivers/gpu/drm/amd/amdkfd/kfd_priv.h +48 -0

78 lines not on this page · raw message

drivers/gpu/drm/amd/amdkfd/kfd_process.c +24 -0
index 945d622..b341656 100644
@@ -178,6 +178,8 @@ static void kfd_process_wq_release(struct work_struct *work)
 		kfree(pdd);
 	}
 
+	kfd_event_free_process(p);
+
 	kfd_pasid_free(p->pasid);
 
 	mutex_unlock(&p->mutex);
@@ -289,6 +291,8 @@ static struct kfd_process *create_process(const struct task_struct *thread)
 
 	INIT_LIST_HEAD(&process->per_device_data);
 
+	kfd_event_init_process(process);
+
 	err = pqm_init(&process->pqm, process);
 	if (err != 0)
 		goto err_process_pqm_init;
@@ -431,3 +435,23 @@ bool kfd_has_process_device_data(struct kfd_process *p)
 {
 	return !(list_empty(&p->per_device_data));
 }
+
+/* This returns with process->mutex locked. */
+struct kfd_process *kfd_lookup_process_by_pasid(unsigned int pasid)
+{
+	struct kfd_process *p;
+	unsigned int temp;
+
+	int idx = srcu_read_lock(&kfd_processes_srcu);
+
+	hash_for_each_rcu(kfd_processes_table, temp, p, kfd_processes) {
+		if (p->pasid == pasid) {
+			mutex_lock(&p->mutex);
+			break;
+		}
+	}
+
+	srcu_read_unlock(&kfd_processes_srcu, idx);
+
+	return p;
+}
Signature · 6 lines
1.9.1

_______________________________________________
dri-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/dri-devel
#4 lore raw

PATCH 5/9 drm/amdkfd: Add memory exception handling

In reply to Oded Gabbay

From: Alexey Skidanov <[email protected]>

This patch adds Peripheral Page Request (PPR) failure processing and reporting.

Bad address or pointer to a system memory block with inappropriate read/write permission cause such PPR failure during a user queue processing. PPR request handling is done by IOMMU driver notifying AMDKFD module on PPR failure.

The process triggering a PPR failure will be notified by appropriate event or SIGTERM signal will be sent to it.

---
 drivers/gpu/drm/amd/amdkfd/kfd_device.c |  29 ++++++
 drivers/gpu/drm/amd/amdkfd/kfd_events.c | 154 ++++++++++++++++++++++++++++++--
 drivers/gpu/drm/amd/amdkfd/kfd_events.h |   7 ++
 drivers/gpu/drm/amd/amdkfd/kfd_priv.h   |   5 +-
 4 files changed, 186 insertions(+), 9 deletions(-)
drivers/gpu/drm/amd/amdkfd/kfd_device.c +29 -0
index 4c03169..52cab0f 100644
@@ -182,6 +182,32 @@ static void iommu_pasid_shutdown_callback(struct pci_dev *pdev, int pasid)
 		kfd_unbind_process_from_device(dev, pasid);
 }
 
+/*
+ * This function called by IOMMU driver on PPR failure
+ */
+static int iommu_invalid_ppr_cb(struct pci_dev *pdev, int pasid,
+		unsigned long address, u16 flags)
+{
+	struct kfd_dev *dev;
+
+	dev_warn(kfd_device,
+			"Invalid PPR device %x:%x.%x pasid %d address 0x%lX flags 0x%X",
+			PCI_BUS_NUM(pdev->devfn),
+			PCI_SLOT(pdev->devfn),
+			PCI_FUNC(pdev->devfn),
+			pasid,
+			address,
+			flags);
+
+	dev = kfd_device_by_pci_dev(pdev);
+	BUG_ON(dev == NULL);
+
+	kfd_signal_iommu_event(dev, pasid, address,
+			flags & PPR_FAULT_WRITE, flags & PPR_FAULT_EXEC);
+
+	return AMD_IOMMU_INV_PRI_RSP_INVALID;
+}
+
 bool kgd2kfd_device_init(struct kfd_dev *kfd,
 			 const struct kgd2kfd_shared_resources *gpu_resources)
 {
@@ -251,6 +277,7 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd,
 	}
 	amd_iommu_set_invalidate_ctx_cb(kfd->pdev,
 						iommu_pasid_shutdown_callback);
+	amd_iommu_set_invalid_ppr_cb(kfd->pdev, iommu_invalid_ppr_cb);
 
 	kfd->dqm = device_queue_manager_init(kfd);
 	if (!kfd->dqm) {
@@ -316,6 +343,7 @@ void kgd2kfd_suspend(struct kfd_dev *kfd)
 	if (kfd->init_complete) {
 		kfd->dqm->ops.stop(kfd->dqm);
 		amd_iommu_set_invalidate_ctx_cb(kfd->pdev, NULL);
+		amd_iommu_set_invalid_ppr_cb(kfd->pdev, NULL);
 		amd_iommu_free_device(kfd->pdev);
 	}
 }
@@ -335,6 +363,7 @@ int kgd2kfd_resume(struct kfd_dev *kfd)
 			return -ENXIO;
 		amd_iommu_set_invalidate_ctx_cb(kfd->pdev,
 						iommu_pasid_shutdown_callback);
+		amd_iommu_set_invalid_ppr_cb(kfd->pdev, iommu_invalid_ppr_cb);
 		kfd->dqm->ops.start(kfd->dqm);
 	}
 
drivers/gpu/drm/amd/amdkfd/kfd_events.c +146 -8

211 lines not on this page · raw message

drivers/gpu/drm/amd/amdkfd/kfd_events.h +7 -0
index d9b5b38..691cf85 100644
@@ -28,6 +28,7 @@
 #include <linux/types.h>
 #include <linux/list.h>
 #include "kfd_priv.h"
+#include <uapi/linux/kfd_ioctl.h>
 
 #define KFD_EVENT_ID_NONSIGNAL_MASK 0x80000000U
 #define KFD_FIRST_NONSIGNAL_EVENT_ID KFD_EVENT_ID_NONSIGNAL_MASK
@@ -61,6 +62,11 @@ struct kfd_event {
 	struct signal_page *signal_page;
 	unsigned int signal_slot_index;
 	uint64_t __user *user_signal_address;
+
+	/* type specific data */
+	union {
+		struct kfd_hsa_memory_exception_data memory_exception_data;
+	};
 };
 
 #define KFD_EVENT_TIMEOUT_IMMEDIATE 0
@@ -69,6 +75,7 @@ struct kfd_event {
 /* Matching HSA_EVENTTYPE */
 #define KFD_EVENT_TYPE_SIGNAL 0
 #define KFD_EVENT_TYPE_DEBUG 5
+#define KFD_EVENT_TYPE_MEMORY 8
 
 extern void kfd_signal_event_interrupt(unsigned int pasid, uint32_t partial_id,
 					uint32_t valid_id_bits);
drivers/gpu/drm/amd/amdkfd/kfd_priv.h +4 -1
index 7f6ea96..8ecc033 100644
@@ -694,11 +694,14 @@ void kfd_event_free_process(struct kfd_process *p);
 int radeon_kfd_event_mmap(struct kfd_process *process,
 				struct vm_area_struct *vma);
 int kfd_wait_on_events(struct kfd_process *p,
-		       uint32_t num_events, const uint32_t __user *event_ids,
+		       uint32_t num_events, void __user *data,
 		       bool all, uint32_t user_timeout_ms,
 		       enum kfd_event_wait_result *wait_result);
 void kfd_signal_event_interrupt(unsigned int pasid, uint32_t partial_id,
 				uint32_t valid_id_bits);
+void kfd_signal_iommu_event(struct kfd_dev *dev,
+		unsigned int pasid, unsigned long address,
+		bool is_write_requested, bool is_execute_requested);
 int kfd_set_event(struct kfd_process *p, uint32_t event_id);
 int kfd_reset_event(struct kfd_process *p, uint32_t event_id);
 int kfd_event_create(struct file *devkfd, struct kfd_process *p,
Signature · 6 lines
1.9.1

_______________________________________________
dri-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/dri-devel
#5 lore raw

PATCH 6/9 drm/amdkfd: Add bad opcode exception handling

In reply to Oded Gabbay

From: Alexey Skidanov <[email protected]>

---
 drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c |  5 ++++-
 drivers/gpu/drm/amd/amdkfd/cik_int.h             |  1 +
 drivers/gpu/drm/amd/amdkfd/kfd_events.c          | 21 +++++++++++++++++++++
 drivers/gpu/drm/amd/amdkfd/kfd_events.h          |  1 +
 drivers/gpu/drm/amd/amdkfd/kfd_priv.h            |  2 ++
 5 files changed, 29 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c +4 -1
index c466dc4..5ddb217 100644
@@ -33,7 +33,8 @@ static bool cik_event_interrupt_isr(struct kfd_dev *dev,
 	/* Do not process in ISR, just request it to be forwarded to WQ. */
 	return (ihre->pasid != 0) &&
 		(ihre->source_id == CIK_INTSRC_CP_END_OF_PIPE ||
-		ihre->source_id == CIK_INTSRC_SQ_INTERRUPT_MSG);
+		ihre->source_id == CIK_INTSRC_SQ_INTERRUPT_MSG ||
+		ihre->source_id == CIK_INTSRC_CP_BAD_OPCODE);
 }
 
 static void cik_event_interrupt_wq(struct kfd_dev *dev,
@@ -49,6 +50,8 @@ static void cik_event_interrupt_wq(struct kfd_dev *dev,
 		kfd_signal_event_interrupt(ihre->pasid, 0, 0);
 	else if (ihre->source_id == CIK_INTSRC_SQ_INTERRUPT_MSG)
 		kfd_signal_event_interrupt(ihre->pasid, ihre->data & 0xFF, 8);
+	else if (ihre->source_id == CIK_INTSRC_CP_BAD_OPCODE)
+		kfd_signal_hw_exception_event(ihre->pasid);
 }
 
 const struct kfd_event_interrupt_class event_interrupt_class_cik = {
drivers/gpu/drm/amd/amdkfd/cik_int.h +1 -0
index af19b3a..122b8f6 100644
@@ -48,6 +48,7 @@ struct cik_ih_ring_entry {
 
 #define CIK_INTSRC_DEQUEUE_COMPLETE	0xC6
 #define CIK_INTSRC_CP_END_OF_PIPE	0xB5
+#define CIK_INTSRC_CP_BAD_OPCODE	0xB7
 #define CIK_INTSRC_SQ_INTERRUPT_MSG	0xEF
 
 #endif
drivers/gpu/drm/amd/amdkfd/kfd_events.c +21 -0
index ac60fb2..9eed7bb 100644
@@ -911,3 +911,24 @@ void kfd_signal_iommu_event(struct kfd_dev *dev, unsigned int pasid,
 	mutex_unlock(&p->event_mutex);
 	mutex_unlock(&p->mutex);
 }
+
+void kfd_signal_hw_exception_event(unsigned int pasid)
+{
+	/*
+	 * Because we are called from arbitrary context (workqueue) as opposed
+	 * to process context, kfd_process could attempt to exit while we are
+	 * running so the lookup function returns a locked process.
+	 */
+	struct kfd_process *p = kfd_lookup_process_by_pasid(pasid);
+
+	if (!p)
+		return; /* Presumably process exited. */
+
+	mutex_lock(&p->event_mutex);
+
+	/* Lookup events by type and signal them */
+	lookup_events_by_type_and_signal(p, KFD_EVENT_TYPE_HW_EXCEPTION, NULL);
+
+	mutex_unlock(&p->event_mutex);
+	mutex_unlock(&p->mutex);
+}
drivers/gpu/drm/amd/amdkfd/kfd_events.h +1 -0
index 691cf85..28f6838 100644
@@ -74,6 +74,7 @@ struct kfd_event {
 
 /* Matching HSA_EVENTTYPE */
 #define KFD_EVENT_TYPE_SIGNAL 0
+#define KFD_EVENT_TYPE_HW_EXCEPTION 3
 #define KFD_EVENT_TYPE_DEBUG 5
 #define KFD_EVENT_TYPE_MEMORY 8
 
drivers/gpu/drm/amd/amdkfd/kfd_priv.h +2 -0
index 8ecc033..fe76b79 100644
@@ -682,6 +682,7 @@ phys_addr_t kfd_get_process_doorbells(struct kfd_dev *dev,
 
 /* Events */
 extern const struct kfd_event_interrupt_class event_interrupt_class_cik;
+extern const struct kfd_device_global_init_class device_global_init_class_cik;
 
 enum kfd_event_wait_result {
 	KFD_WAIT_COMPLETE,
@@ -702,6 +703,7 @@ void kfd_signal_event_interrupt(unsigned int pasid, uint32_t partial_id,
 void kfd_signal_iommu_event(struct kfd_dev *dev,
 		unsigned int pasid, unsigned long address,
 		bool is_write_requested, bool is_execute_requested);
+void kfd_signal_hw_exception_event(unsigned int pasid);
 int kfd_set_event(struct kfd_process *p, uint32_t event_id);
 int kfd_reset_event(struct kfd_process *p, uint32_t event_id);
 int kfd_event_create(struct file *devkfd, struct kfd_process *p,
Signature · 6 lines
1.9.1

_______________________________________________
dri-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/dri-devel
#6 lore raw

PATCH 7/9 drm/amdkfd: Add module parameter of send_sigterm

In reply to Oded Gabbay

This patch adds a new kernel module parameter to amdkfd, called send_sigterm.

This parameter specifies whether amdkfd should send the SIGTERM signal to an HSA process, when the following conditions occur:

1. The GPU triggers an exception regarding a kernel that was issued by this process.

2. The HSA process isn't waiting on an event that handles this exception.

The default behavior is not to send a SIGTERM and suffice with a dmesg error print.

---
 drivers/gpu/drm/amd/amdkfd/kfd_events.c | 12 +++++++++---
 drivers/gpu/drm/amd/amdkfd/kfd_module.c |  5 +++++
 drivers/gpu/drm/amd/amdkfd/kfd_priv.h   |  6 ++++++
 3 files changed, 20 insertions(+), 3 deletions(-)
drivers/gpu/drm/amd/amdkfd/kfd_events.c +9 -3
index 9eed7bb..e52376b 100644
@@ -847,10 +847,16 @@ static void lookup_events_by_type_and_signal(struct kfd_process *p,
 
 	/* Send SIGTERM no event of type "type" has been found*/
 	if (send_signal) {
-		dev_warn(kfd_device,
-			"Sending SIGTERM to HSA Process with PID %d ",
+		if (send_sigterm) {
+			dev_warn(kfd_device,
+				"Sending SIGTERM to HSA Process with PID %d ",
+					p->lead_thread->pid);
+			send_sig(SIGTERM, p->lead_thread, 0);
+		} else {
+			dev_err(kfd_device,
+				"HSA Process (PID %d) got unhandled exception",
 				p->lead_thread->pid);
-		send_sig(SIGTERM, p->lead_thread, 0);
+		}
 	}
 }
 
drivers/gpu/drm/amd/amdkfd/kfd_module.c +5 -0
index 4e0a68f..e4fc96e 100644
@@ -54,6 +54,11 @@ module_param(max_num_of_queues_per_device, int, 0444);
 MODULE_PARM_DESC(max_num_of_queues_per_device,
 	"Maximum number of supported queues per device (1 = Minimum, 4096 = default)");
 
+int send_sigterm;
+module_param(send_sigterm, int, 0444);
+MODULE_PARM_DESC(send_sigterm,
+	"Send sigterm to HSA process on unhandled exception (0 = disable, 1 = enable)");
+
 bool kgd2kfd_init(unsigned interface_version, const struct kgd2kfd_calls **g2f)
 {
 	/*
drivers/gpu/drm/amd/amdkfd/kfd_priv.h +6 -0
index fe76b79..bd435a7 100644
@@ -74,6 +74,12 @@ extern int max_num_of_queues_per_device;
 /* Kernel module parameter to specify the scheduling policy */
 extern int sched_policy;
 
+/*
+ * Kernel module parameter to specify whether to send sigterm to HSA process on
+ * unhandled exception
+ */
+extern int send_sigterm;
+
 /**
  * enum kfd_sched_policy
  *
Signature · 6 lines
1.9.1

_______________________________________________
dri-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/dri-devel
#7 lore raw

PATCH 8/9 drm/amdkfd: Implement events IOCTLs

In reply to Oded Gabbay

From: Andrew Lewycky <[email protected]>

---
 drivers/gpu/drm/amd/amdkfd/kfd_chardev.c | 36 +++++++++++++++++++++++++++-----
 1 file changed, 31 insertions(+), 5 deletions(-)
drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +31 -5
index d0630cc..c69953c 100644
@@ -519,31 +519,57 @@ static int kfd_ioctl_get_process_apertures(struct file *filp,
 static int kfd_ioctl_create_event(struct file *filp, struct kfd_process *p,
 					void *data)
 {
-	return -ENODEV;
+	struct kfd_ioctl_create_event_args *args = data;
+	int err;
+
+	err = kfd_event_create(filp, p, args->event_type,
+				args->auto_reset != 0, args->node_id,
+				&args->event_id, &args->event_trigger_data,
+				&args->event_page_offset,
+				&args->event_slot_index);
+
+	return err;
 }
 
 static int kfd_ioctl_destroy_event(struct file *filp, struct kfd_process *p,
 					void *data)
 {
-	return -ENODEV;
+	struct kfd_ioctl_destroy_event_args *args = data;
+
+	return kfd_event_destroy(p, args->event_id);
 }
 
 static int kfd_ioctl_set_event(struct file *filp, struct kfd_process *p,
 				void *data)
 {
-	return -ENODEV;
+	struct kfd_ioctl_set_event_args *args = data;
+
+	return kfd_set_event(p, args->event_id);
 }
 
 static int kfd_ioctl_reset_event(struct file *filp, struct kfd_process *p,
 				void *data)
 {
-	return -ENODEV;
+	struct kfd_ioctl_reset_event_args *args = data;
+
+	return kfd_reset_event(p, args->event_id);
 }
 
 static int kfd_ioctl_wait_events(struct file *filp, struct kfd_process *p,
 				void *data)
 {
-	return -ENODEV;
+	struct kfd_ioctl_wait_events_args *args = data;
+	enum kfd_event_wait_result wait_result;
+	int err;
+
+	err = kfd_wait_on_events(p, args->num_events,
+			(void __user *)args->events_ptr,
+			(args->wait_for_all != 0),
+			args->timeout, &wait_result);
+
+	args->wait_result = wait_result;
+
+	return err;
 }
 
 #define AMDKFD_IOCTL_DEF(ioctl, _func, _flags) \
Signature · 6 lines
1.9.1

_______________________________________________
dri-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/dri-devel
#8 lore raw

PATCH 9/9 drm/amdkfd: change driver version to 0.7.2

In reply to Oded Gabbay
---
 drivers/gpu/drm/amd/amdkfd/kfd_module.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/gpu/drm/amd/amdkfd/kfd_module.c +2 -2
index e4fc96e..ca8410e 100644
@@ -29,10 +29,10 @@
 #define KFD_DRIVER_AUTHOR	"AMD Inc. and others"
 
 #define KFD_DRIVER_DESC		"Standalone HSA driver for AMD's GPUs"
-#define KFD_DRIVER_DATE		"20150122"
+#define KFD_DRIVER_DATE		"20150421"
 #define KFD_DRIVER_MAJOR	0
 #define KFD_DRIVER_MINOR	7
-#define KFD_DRIVER_PATCHLEVEL	1
+#define KFD_DRIVER_PATCHLEVEL	2
 
 static const struct kgd2kfd_calls kgd2kfd = {
 	.exit		= kgd2kfd_exit,
Signature · 6 lines
1.9.1

_______________________________________________
dri-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/dri-devel