Skip to contentSkip to conversation

Add Interrupts & Events modules to amdkfd

PATCH New Oded Gabbay 1 participant 10 messages May 10, 2015

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

v2 cover Add Interrupts & Events modules to amdkfd

This is the second version of this patch-set.

Only two patches were changed from the first version:

- drm/amdkfd: add events IOCTL set definitions
- drm/amdkfd: Add the events module

Please review,

Thanks

Oded

Alexey Skidanov (2):
drm/amdkfd: Add memory exception handling
drm/amdkfd: Add bad opcode exception handling

Andrew Lewycky (3):
drm/amdkfd: Add interrupt handling module
drm/amdkfd: add events IOCTL set definitions
drm/amdkfd: Implement events IOCTLs

Oded Gabbay (4):
drm/radeon: Add init interrupt kfd->kgd interface drm/amdkfd: Add the events module drm/amdkfd: Add module parameter of send_sigterm drm/amdkfd: change driver version to 0.7.2

 drivers/gpu/drm/amd/amdkfd/Makefile                |   1 +
 drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c   |  66 ++
 drivers/gpu/drm/amd/amdkfd/cik_int.h               |  41 +
 drivers/gpu/drm/amd/amdkfd/kfd_chardev.c           |  87 +-
 drivers/gpu/drm/amd/amdkfd/kfd_device.c            |  52 +-
 .../gpu/drm/amd/amdkfd/kfd_device_queue_manager.c  |  15 +
 drivers/gpu/drm/amd/amdkfd/kfd_events.c            | 954 +++++++++++++++++++++
 drivers/gpu/drm/amd/amdkfd/kfd_events.h            |  84 ++
 drivers/gpu/drm/amd/amdkfd/kfd_interrupt.c         | 188 ++++
 drivers/gpu/drm/amd/amdkfd/kfd_module.c            |   9 +-
 drivers/gpu/drm/amd/amdkfd/kfd_priv.h              |  75 ++
 drivers/gpu/drm/amd/amdkfd/kfd_process.c           |  24 +
 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 +-
 include/uapi/linux/kfd_ioctl.h                     |  96 ++-
 17 files changed, 1710 insertions(+), 8 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
 create mode 100644 drivers/gpu/drm/amd/amdkfd/kfd_interrupt.c
Signature · 6 lines
1.9.1

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

PATCH v2 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
#2 lore raw

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

In reply to Oded Gabbay

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 1eb1022..078092c 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;
 }
 
@@ -737,6 +749,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
#3 lore raw

PATCH v2 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

v2:

- Move the limit of the signal events to kfd_ioctl.h so it can be used by userspace
- Increase limit of signal events to 4096

---
 drivers/gpu/drm/amd/amdkfd/kfd_chardev.c | 45 +++++++++++++++
 include/uapi/linux/kfd_ioctl.h           | 96 +++++++++++++++++++++++++++++++-
 2 files changed, 139 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 +94 -2

114 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
#4 lore raw

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

In reply to Oded Gabbay

This patch adds the events module (kfd_events.c) and the interrupt handle 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.

v2:

Increase limit of signal events to 4096 per process Remove bitfields from struct cik_ih_ring_entry
Rename radeon_kfd_event_mmap to kfd_event_mmap
Add debug prints to allocate_free_slot and allocate_signal_page Make allocate_event_notification_slot return a correct value Add warning prints to create_signal_event
Remove error print from IOCTL path
Reformatted debug prints in kfd_event_mmap
Map correct size (as received from mmap) in kfd_event_mmap

---
 drivers/gpu/drm/amd/amdkfd/Makefile              |   2 +-
 drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c |  63 ++
 drivers/gpu/drm/amd/amdkfd/cik_int.h             |  40 ++
 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          | 788 +++++++++++++++++++++++
 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            |  47 ++
 drivers/gpu/drm/amd/amdkfd/kfd_process.c         |  24 +
 10 files changed, 1063 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 +63 -0

63 lines not on this page · raw message

drivers/gpu/drm/amd/amdkfd/cik_int.h new file +40 -0
new file mode 100644
index 0000000..bbef9e2
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef HSA_RADEON_CIK_INT_H_INCLUDED
+#define HSA_RADEON_CIK_INT_H_INCLUDED
+
+#include <linux/types.h>
+
+struct cik_ih_ring_entry {
+	uint32_t source_id;
+	uint32_t data;
+	uint32_t ring_id;
+	uint32_t reserved;
+};
+
+#define CIK_INTSRC_DEQUEUE_COMPLETE	0xC6
+#define CIK_INTSRC_CP_END_OF_PIPE	0xB5
+#define CIK_INTSRC_SQ_INTERRUPT_MSG	0xEF
+
+#endif
+
drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +14 -2
index 9933b2e..6dd8948 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 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 +788 -0

788 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 +47 -0

77 lines not on this page · raw message

drivers/gpu/drm/amd/amdkfd/kfd_process.c +24 -0
index 4d7bc95..dc910af 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);
@@ -288,6 +290,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;
@@ -430,3 +434,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
#5 lore raw

PATCH v2 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 | 155 ++++++++++++++++++++++++++++++--
 drivers/gpu/drm/amd/amdkfd/kfd_events.h |   7 ++
 drivers/gpu/drm/amd/amdkfd/kfd_priv.h   |   5 +-
 4 files changed, 187 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 +147 -8

212 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 0ff9a3d..3594503 100644
@@ -693,11 +693,14 @@ void kfd_event_init_process(struct kfd_process *p);
 void kfd_event_free_process(struct kfd_process *p);
 int 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
#6 lore raw

PATCH v2 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 629510a..211fc48 100644
@@ -36,7 +36,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 (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,
@@ -55,6 +56,8 @@ static void cik_event_interrupt_wq(struct kfd_dev *dev,
 		kfd_signal_event_interrupt(pasid, 0, 0);
 	else if (ihre->source_id == CIK_INTSRC_SQ_INTERRUPT_MSG)
 		kfd_signal_event_interrupt(pasid, ihre->data & 0xFF, 8);
+	else if (ihre->source_id == CIK_INTSRC_CP_BAD_OPCODE)
+		kfd_signal_hw_exception_event(pasid);
 }
 
 const struct kfd_event_interrupt_class event_interrupt_class_cik = {
drivers/gpu/drm/amd/amdkfd/cik_int.h +1 -0
index bbef9e2..79a16d2 100644
@@ -34,6 +34,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 3a64de1..f0a3f4e 100644
@@ -925,3 +925,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 3594503..9383494 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,
@@ -701,6 +702,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
#7 lore raw

PATCH v2 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 f0a3f4e..2f3ebc5 100644
@@ -861,10 +861,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 9383494..b6f838f 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
#8 lore raw

PATCH v2 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 6dd8948..b2c6109 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
#9 lore raw

PATCH v2 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