aboutsummaryrefslogtreecommitdiffstats
path: root/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71/1204-drm-amdkfd-fix-zero-reading-of-VMID-and-PASID-for-Ha.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71/1204-drm-amdkfd-fix-zero-reading-of-VMID-and-PASID-for-Ha.patch')
-rw-r--r--meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71/1204-drm-amdkfd-fix-zero-reading-of-VMID-and-PASID-for-Ha.patch138
1 files changed, 138 insertions, 0 deletions
diff --git a/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71/1204-drm-amdkfd-fix-zero-reading-of-VMID-and-PASID-for-Ha.patch b/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71/1204-drm-amdkfd-fix-zero-reading-of-VMID-and-PASID-for-Ha.patch
new file mode 100644
index 00000000..6c299502
--- /dev/null
+++ b/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71/1204-drm-amdkfd-fix-zero-reading-of-VMID-and-PASID-for-Ha.patch
@@ -0,0 +1,138 @@
+From cec72030b4055555715f22297303a4656e0c5470 Mon Sep 17 00:00:00 2001
+From: Lan Xiao <Lan.Xiao@amd.com>
+Date: Thu, 13 Oct 2016 16:03:33 -0400
+Subject: [PATCH 1204/4131] drm/amdkfd: fix zero reading of VMID and PASID for
+ Hawaii
+
+Upon VM Fault, the VMID and PASID written by HW are zeros in
+Hawaii. Instead of reading from ih_ring_entry, read directly
+from the registers. This workaround fix the soft hang issues
+caused by mishandled VM Fault in Hawaii.
+
+Fix BUG: SWDEV-100220
+
+Change-Id: I1c89263e4bccde037d24f71f3efef7903d83d2f0
+Signed-off-by: Lan Xiao <Lan.Xiao@amd.com>
+---
+ drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c | 24 +++++++++++++++++++++++-
+ drivers/gpu/drm/amd/amdkfd/kfd_device.c | 9 +++++++--
+ drivers/gpu/drm/amd/amdkfd/kfd_interrupt.c | 7 +++++--
+ drivers/gpu/drm/amd/amdkfd/kfd_priv.h | 7 +++++--
+ 4 files changed, 40 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c b/drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c
+index 3f49f8e..c60a71a 100644
+--- a/drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c
++++ b/drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c
+@@ -37,12 +37,34 @@ static bool is_cpc_vm_fault(struct kfd_dev *dev,
+ return true;
+ return false;
+ }
++
+ static bool cik_event_interrupt_isr(struct kfd_dev *dev,
+- const uint32_t *ih_ring_entry)
++ const uint32_t *ih_ring_entry,
++ uint32_t *patched_ihre,
++ bool *patched_flag)
+ {
+ const struct cik_ih_ring_entry *ihre =
+ (const struct cik_ih_ring_entry *)ih_ring_entry;
++ const struct kfd2kgd_calls *f2g = dev->kfd2kgd;
++ struct cik_ih_ring_entry *tmp_ihre =
++ (struct cik_ih_ring_entry *) patched_ihre;
++
++ /* This workaround is due to HW/FW limitation on Hawaii that
++ * VMID and PASID are not written into ih_ring_entry
++ */
++ if ((ihre->source_id == CIK_INTSRC_GFX_PAGE_INV_FAULT ||
++ ihre->source_id == CIK_INTSRC_GFX_MEM_PROT_FAULT) &&
++ dev->device_info->asic_family == CHIP_HAWAII) {
++ *patched_flag = true;
++ *tmp_ihre = *ihre;
+
++ tmp_ihre->vmid = f2g->read_vmid_from_vmfault_reg(dev->kgd);
++ tmp_ihre->pasid = f2g->get_atc_vmid_pasid_mapping_pasid(
++ dev->kgd, tmp_ihre->vmid);
++ return (tmp_ihre->pasid != 0) &&
++ tmp_ihre->vmid >= dev->vm_info.first_vmid_kfd &&
++ tmp_ihre->vmid <= dev->vm_info.last_vmid_kfd;
++ }
+ /* 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 ||
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c
+index 6bab9db..dbbe3cf 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c
+@@ -674,14 +674,19 @@ static int kfd_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)
+ {
++ uint32_t patched_ihre[DIV_ROUND_UP(
++ kfd->device_info->ih_ring_entry_size,
++ sizeof(uint32_t))];
++ bool is_patched = false;
++
+ 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))
++ && interrupt_is_wanted(kfd, ih_ring_entry, patched_ihre, &is_patched)
++ && enqueue_ih_ring_entry(kfd, is_patched ? patched_ihre : ih_ring_entry))
+ queue_work(kfd->ih_wq, &kfd->interrupt_work);
+
+ spin_unlock(&kfd->interrupt_lock);
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_interrupt.c b/drivers/gpu/drm/amd/amdkfd/kfd_interrupt.c
+index 4d1639f..d737df0 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_interrupt.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_interrupt.c
+@@ -148,12 +148,15 @@ static void interrupt_wq(struct work_struct *work)
+ 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)
++bool interrupt_is_wanted(struct kfd_dev *dev,
++ const uint32_t *ih_ring_entry,
++ uint32_t *patched_ihre, bool *flag)
+ {
+ /* 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);
++ wanted |= dev->device_info->event_interrupt_class->interrupt_isr(dev,
++ ih_ring_entry, patched_ihre, flag);
+
+ return wanted != 0;
+ }
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
+index 107c573..11f918c 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
+@@ -175,7 +175,8 @@ enum asic_family_type {
+ (chip) == CHIP_HAWAII)
+
+ struct kfd_event_interrupt_class {
+- bool (*interrupt_isr)(struct kfd_dev *dev, const uint32_t *ih_ring_entry);
++ bool (*interrupt_isr)(struct kfd_dev *dev, const uint32_t *ih_ring_entry,
++ uint32_t *patched_ihre, bool *patched_flag);
+ void (*interrupt_wq)(struct kfd_dev *dev, const uint32_t *ih_ring_entry);
+ };
+
+@@ -805,7 +806,9 @@ 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);
++bool interrupt_is_wanted(struct kfd_dev *dev,
++ const uint32_t *ih_ring_entry,
++ uint32_t *patched_ihre, bool *flag);
+
+ /* Power Management */
+ void kgd2kfd_suspend(struct kfd_dev *kfd);
+--
+2.7.4
+