aboutsummaryrefslogtreecommitdiffstats
path: root/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71/5673-drm-amdkfd-Add-sanity-checks-in-IRQ-handlers.patch
blob: 106a63582942076628030288a97869202916e85c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
From 8042b50efc0c528f43bfff0400c0d7323a93fe26 Mon Sep 17 00:00:00 2001
From: Felix Kuehling <Felix.Kuehling@amd.com>
Date: Mon, 30 Apr 2018 19:22:49 -0400
Subject: [PATCH 5673/5725] drm/amdkfd: Add sanity checks in IRQ handlers

Only accept interrupts from KFD VMIDs. Just checking for a PASID may
not be enough because amdgpu started using PASIDs to map VM faults
to processes.

Warn if an IRQ doesn't have a valid PASID (indicating a firmware bug).

Change-Id: I34ca5b4b03ffe51a23d03490fc65b6c946bbbf51
Suggested-by: Shaoyun Liu <Shaoyun.Liu@amd.com>
Suggested-by: Oak Zeng <Oak.Zeng@amd.com>
Signed-off-by: Felix Kuehling <Felix.Kuehling@amd.com>
---
 drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c | 33 +++++++++---------
 drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c  | 44 ++++++++++++++----------
 2 files changed, 43 insertions(+), 34 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c b/drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c
index 1261432..5d2475d 100644
--- a/drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c
+++ b/drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c
@@ -24,15 +24,6 @@
 #include "kfd_events.h"
 #include "cik_int.h"
 
-static bool is_cpc_vm_fault(struct kfd_dev *dev, uint32_t source_id,
-			    unsigned int vmid)
-{
-	return (source_id == CIK_INTSRC_GFX_PAGE_INV_FAULT ||
-		source_id == CIK_INTSRC_GFX_MEM_PROT_FAULT) &&
-		vmid >= dev->vm_info.first_vmid_kfd &&
-		vmid <= dev->vm_info.last_vmid_kfd;
-}
-
 static bool cik_event_interrupt_isr(struct kfd_dev *dev,
 					const uint32_t *ih_ring_entry,
 					uint32_t *patched_ihre,
@@ -67,16 +58,26 @@ static bool cik_event_interrupt_isr(struct kfd_dev *dev,
 			vmid <= dev->vm_info.last_vmid_kfd;
 	}
 
+	/* Only handle interrupts from KFD VMIDs */
 	vmid  = (ihre->ring_id & 0x0000ff00) >> 8;
+	if (vmid < dev->vm_info.first_vmid_kfd ||
+	    vmid > dev->vm_info.last_vmid_kfd)
+		return 0;
+
+	/* If there is no valid PASID, it's likely a firmware bug */
 	pasid = (ihre->ring_id & 0xffff0000) >> 16;
+	if (WARN_ONCE(pasid == 0, "FW bug: No PASID in KFD interrupt"))
+		return 0;
 
-	/* 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_SDMA_TRAP ||
-		 ihre->source_id == CIK_INTSRC_SQ_INTERRUPT_MSG ||
-		 ihre->source_id == CIK_INTSRC_CP_BAD_OPCODE ||
-		 is_cpc_vm_fault(dev, ihre->source_id, vmid));
+	/* Interrupt types we care about: various signals and faults.
+	 * They will be forwarded to a work queue (see below).
+	 */
+	return ihre->source_id == CIK_INTSRC_CP_END_OF_PIPE ||
+		ihre->source_id == CIK_INTSRC_SDMA_TRAP ||
+		ihre->source_id == CIK_INTSRC_SQ_INTERRUPT_MSG ||
+		ihre->source_id == CIK_INTSRC_CP_BAD_OPCODE ||
+		ihre->source_id == CIK_INTSRC_GFX_PAGE_INV_FAULT ||
+		ihre->source_id == CIK_INTSRC_GFX_MEM_PROT_FAULT;
 }
 
 static void cik_event_interrupt_wq(struct kfd_dev *dev,
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c b/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c
index 5217e51..f836897 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c
@@ -31,29 +31,37 @@ static bool event_interrupt_isr_v9(struct kfd_dev *dev,
 					bool *patched_flag)
 {
 	uint16_t source_id, client_id, pasid, vmid;
+	const uint32_t *data = ih_ring_entry;
 
-	source_id = SOC15_SOURCE_ID_FROM_IH_ENTRY(ih_ring_entry);
-	client_id = SOC15_CLIENT_ID_FROM_IH_ENTRY(ih_ring_entry);
-	pasid = SOC15_PASID_FROM_IH_ENTRY(ih_ring_entry);
+	/* Only handle interrupts from KFD VMIDs */
 	vmid = SOC15_VMID_FROM_IH_ENTRY(ih_ring_entry);
+	if (vmid < dev->vm_info.first_vmid_kfd ||
+	    vmid > dev->vm_info.last_vmid_kfd)
+		return 0;
+
+	/* If there is no valid PASID, it's likely a firmware bug */
+	pasid = SOC15_PASID_FROM_IH_ENTRY(ih_ring_entry);
+	if (WARN_ONCE(pasid == 0, "FW bug: No PASID in KFD interrupt"))
+		return 0;
 
-	if (pasid) {
-		const uint32_t *data = ih_ring_entry;
+	source_id = SOC15_SOURCE_ID_FROM_IH_ENTRY(ih_ring_entry);
+	client_id = SOC15_CLIENT_ID_FROM_IH_ENTRY(ih_ring_entry);
 
-		pr_debug("client id 0x%x, source id %d, pasid 0x%x. raw data:\n",
-			 client_id, source_id, pasid);
-		pr_debug("%8X, %8X, %8X, %8X, %8X, %8X, %8X, %8X.\n",
-			 data[0], data[1], data[2], data[3],
-			 data[4], data[5], data[6], data[7]);
-	}
+	pr_debug("client id 0x%x, source id %d, pasid 0x%x. raw data:\n",
+		 client_id, source_id, pasid);
+	pr_debug("%8X, %8X, %8X, %8X, %8X, %8X, %8X, %8X.\n",
+		 data[0], data[1], data[2], data[3],
+		 data[4], data[5], data[6], data[7]);
 
-	return (pasid != 0) &&
-		(source_id == SOC15_INTSRC_CP_END_OF_PIPE ||
-		 source_id == SOC15_INTSRC_SDMA_TRAP ||
-		 source_id == SOC15_INTSRC_SQ_INTERRUPT_MSG ||
-		 source_id == SOC15_INTSRC_CP_BAD_OPCODE ||
-		 client_id == SOC15_IH_CLIENTID_VMC ||
-		 client_id == SOC15_IH_CLIENTID_UTCL2);
+	/* Interrupt types we care about: various signals and faults.
+	 * They will be forwarded to a work queue (see below).
+	 */
+	return source_id == SOC15_INTSRC_CP_END_OF_PIPE ||
+		source_id == SOC15_INTSRC_SDMA_TRAP ||
+		source_id == SOC15_INTSRC_SQ_INTERRUPT_MSG ||
+		source_id == SOC15_INTSRC_CP_BAD_OPCODE ||
+		client_id == SOC15_IH_CLIENTID_VMC ||
+		client_id == SOC15_IH_CLIENTID_UTCL2;
 }
 
 static void event_interrupt_wq_v9(struct kfd_dev *dev,
-- 
2.7.4