Commit | Line | Data |
---|---|---|
cc009e61 MJ |
1 | /* |
2 | * Copyright 2021 Advanced Micro Devices, Inc. | |
3 | * | |
4 | * Permission is hereby granted, free of charge, to any person obtaining a | |
5 | * copy of this software and associated documentation files (the "Software"), | |
6 | * to deal in the Software without restriction, including without limitation | |
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
8 | * and/or sell copies of the Software, and to permit persons to whom the | |
9 | * Software is furnished to do so, subject to the following conditions: | |
10 | * | |
11 | * The above copyright notice and this permission notice shall be included in | |
12 | * all copies or substantial portions of the Software. | |
13 | * | |
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | |
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | |
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |
20 | * OTHER DEALINGS IN THE SOFTWARE. | |
21 | */ | |
22 | ||
23 | #include "kfd_priv.h" | |
24 | #include "kfd_events.h" | |
25 | #include "soc15_int.h" | |
26 | #include "kfd_device_queue_manager.h" | |
27 | #include "ivsrcid/vmc/irqsrcs_vmc_1_0.h" | |
28 | #include "kfd_smi_events.h" | |
12fb1ad7 | 29 | #include "kfd_debug.h" |
cc009e61 MJ |
30 | |
31 | /* | |
32 | * GFX11 SQ Interrupts | |
33 | * | |
34 | * There are 3 encoding types of interrupts sourced from SQ sent as a 44-bit | |
35 | * packet to the Interrupt Handler: | |
36 | * Auto - Generated by the SQG (various cmd overflows, timestamps etc) | |
37 | * Wave - Generated by S_SENDMSG through a shader program | |
38 | * Error - HW generated errors (Illegal instructions, Memviols, EDC etc) | |
39 | * | |
40 | * The 44-bit packet is mapped as {context_id1[7:0],context_id0[31:0]} plus | |
41 | * 4-bits for VMID (SOC15_VMID_FROM_IH_ENTRY) as such: | |
42 | * | |
43 | * - context_id1[7:6] | |
44 | * Encoding type (0 = Auto, 1 = Wave, 2 = Error) | |
45 | * | |
46 | * - context_id0[26] | |
47 | * PRIV bit indicates that Wave S_SEND or error occurred within trap | |
48 | * | |
49 | * - context_id0[24:0] | |
50 | * 25-bit data with the following layout per encoding type: | |
51 | * Auto - only context_id0[8:0] is used, which reports various interrupts | |
52 | * generated by SQG. The rest is 0. | |
53 | * Wave - user data sent from m0 via S_SENDMSG (context_id0[23:0]) | |
54 | * Error - Error Type (context_id0[24:21]), Error Details (context_id0[20:0]) | |
55 | * | |
56 | * The other context_id bits show coordinates (SE/SH/CU/SIMD/WGP) for wave | |
57 | * S_SENDMSG and Errors. These are 0 for Auto. | |
58 | */ | |
59 | ||
60 | enum SQ_INTERRUPT_WORD_ENCODING { | |
61 | SQ_INTERRUPT_WORD_ENCODING_AUTO = 0x0, | |
62 | SQ_INTERRUPT_WORD_ENCODING_INST, | |
63 | SQ_INTERRUPT_WORD_ENCODING_ERROR, | |
64 | }; | |
65 | ||
66 | enum SQ_INTERRUPT_ERROR_TYPE { | |
67 | SQ_INTERRUPT_ERROR_TYPE_EDC_FUE = 0x0, | |
68 | SQ_INTERRUPT_ERROR_TYPE_ILLEGAL_INST, | |
69 | SQ_INTERRUPT_ERROR_TYPE_MEMVIOL, | |
70 | SQ_INTERRUPT_ERROR_TYPE_EDC_FED, | |
71 | }; | |
72 | ||
73 | /* SQ_INTERRUPT_WORD_AUTO_CTXID */ | |
74 | #define SQ_INTERRUPT_WORD_AUTO_CTXID0__THREAD_TRACE__SHIFT 0 | |
75 | #define SQ_INTERRUPT_WORD_AUTO_CTXID0__WLT__SHIFT 1 | |
76 | #define SQ_INTERRUPT_WORD_AUTO_CTXID0__THREAD_TRACE_BUF_FULL__SHIFT 2 | |
77 | #define SQ_INTERRUPT_WORD_AUTO_CTXID0__REG_TIMESTAMP__SHIFT 3 | |
78 | #define SQ_INTERRUPT_WORD_AUTO_CTXID0__CMD_TIMESTAMP__SHIFT 4 | |
79 | #define SQ_INTERRUPT_WORD_AUTO_CTXID0__HOST_CMD_OVERFLOW__SHIFT 5 | |
80 | #define SQ_INTERRUPT_WORD_AUTO_CTXID0__HOST_REG_OVERFLOW__SHIFT 6 | |
81 | #define SQ_INTERRUPT_WORD_AUTO_CTXID0__IMMED_OVERFLOW__SHIFT 7 | |
82 | #define SQ_INTERRUPT_WORD_AUTO_CTXID0__THREAD_TRACE_UTC_ERROR__SHIFT 8 | |
83 | #define SQ_INTERRUPT_WORD_AUTO_CTXID1__ENCODING__SHIFT 6 | |
84 | ||
85 | #define SQ_INTERRUPT_WORD_AUTO_CTXID0__THREAD_TRACE_MASK 0x00000001 | |
86 | #define SQ_INTERRUPT_WORD_AUTO_CTXID0__WLT_MASK 0x00000002 | |
87 | #define SQ_INTERRUPT_WORD_AUTO_CTXID0__THREAD_TRACE_BUF_FULL_MASK 0x00000004 | |
88 | #define SQ_INTERRUPT_WORD_AUTO_CTXID0__REG_TIMESTAMP_MASK 0x00000008 | |
89 | #define SQ_INTERRUPT_WORD_AUTO_CTXID0__CMD_TIMESTAMP_MASK 0x00000010 | |
90 | #define SQ_INTERRUPT_WORD_AUTO_CTXID0__HOST_CMD_OVERFLOW_MASK 0x00000020 | |
91 | #define SQ_INTERRUPT_WORD_AUTO_CTXID0__HOST_REG_OVERFLOW_MASK 0x00000040 | |
92 | #define SQ_INTERRUPT_WORD_AUTO_CTXID0__IMMED_OVERFLOW_MASK 0x00000080 | |
93 | #define SQ_INTERRUPT_WORD_AUTO_CTXID0__THREAD_TRACE_UTC_ERROR_MASK 0x00000100 | |
94 | #define SQ_INTERRUPT_WORD_AUTO_CTXID1__ENCODING_MASK 0x000000c0 | |
95 | ||
96 | /* SQ_INTERRUPT_WORD_WAVE_CTXID */ | |
97 | #define SQ_INTERRUPT_WORD_WAVE_CTXID0__DATA__SHIFT 0 | |
98 | #define SQ_INTERRUPT_WORD_WAVE_CTXID0__SH_ID__SHIFT 25 | |
99 | #define SQ_INTERRUPT_WORD_WAVE_CTXID0__PRIV__SHIFT 26 | |
100 | #define SQ_INTERRUPT_WORD_WAVE_CTXID0__WAVE_ID__SHIFT 27 | |
101 | #define SQ_INTERRUPT_WORD_WAVE_CTXID1__SIMD_ID__SHIFT 0 | |
102 | #define SQ_INTERRUPT_WORD_WAVE_CTXID1__WGP_ID__SHIFT 2 | |
103 | #define SQ_INTERRUPT_WORD_WAVE_CTXID1__ENCODING__SHIFT 6 | |
104 | ||
105 | #define SQ_INTERRUPT_WORD_WAVE_CTXID0__DATA_MASK 0x00ffffff /* [23:0] */ | |
106 | #define SQ_INTERRUPT_WORD_WAVE_CTXID0__SH_ID_MASK 0x02000000 /* [25] */ | |
107 | #define SQ_INTERRUPT_WORD_WAVE_CTXID0__PRIV_MASK 0x04000000 /* [26] */ | |
108 | #define SQ_INTERRUPT_WORD_WAVE_CTXID0__WAVE_ID_MASK 0xf8000000 /* [31:27] */ | |
109 | #define SQ_INTERRUPT_WORD_WAVE_CTXID1__SIMD_ID_MASK 0x00000003 /* [33:32] */ | |
110 | #define SQ_INTERRUPT_WORD_WAVE_CTXID1__WGP_ID_MASK 0x0000003c /* [37:34] */ | |
111 | #define SQ_INTERRUPT_WORD_WAVE_CTXID1__ENCODING_MASK 0x000000c0 /* [39:38] */ | |
112 | ||
113 | /* SQ_INTERRUPT_WORD_ERROR_CTXID */ | |
114 | #define SQ_INTERRUPT_WORD_ERROR_CTXID0__DETAIL__SHIFT 0 | |
115 | #define SQ_INTERRUPT_WORD_ERROR_CTXID0__TYPE__SHIFT 21 | |
116 | #define SQ_INTERRUPT_WORD_ERROR_CTXID0__SH_ID__SHIFT 25 | |
117 | #define SQ_INTERRUPT_WORD_ERROR_CTXID0__PRIV__SHIFT 26 | |
118 | #define SQ_INTERRUPT_WORD_ERROR_CTXID0__WAVE_ID__SHIFT 27 | |
119 | #define SQ_INTERRUPT_WORD_ERROR_CTXID1__SIMD_ID__SHIFT 0 | |
120 | #define SQ_INTERRUPT_WORD_ERROR_CTXID1__WGP_ID__SHIFT 2 | |
121 | #define SQ_INTERRUPT_WORD_ERROR_CTXID1__ENCODING__SHIFT 6 | |
122 | ||
123 | #define SQ_INTERRUPT_WORD_ERROR_CTXID0__DETAIL_MASK 0x001fffff /* [20:0] */ | |
124 | #define SQ_INTERRUPT_WORD_ERROR_CTXID0__TYPE_MASK 0x01e00000 /* [24:21] */ | |
125 | #define SQ_INTERRUPT_WORD_ERROR_CTXID0__SH_ID_MASK 0x02000000 /* [25] */ | |
126 | #define SQ_INTERRUPT_WORD_ERROR_CTXID0__PRIV_MASK 0x04000000 /* [26] */ | |
127 | #define SQ_INTERRUPT_WORD_ERROR_CTXID0__WAVE_ID_MASK 0xf8000000 /* [31:27] */ | |
128 | #define SQ_INTERRUPT_WORD_ERROR_CTXID1__SIMD_ID_MASK 0x00000003 /* [33:32] */ | |
129 | #define SQ_INTERRUPT_WORD_ERROR_CTXID1__WGP_ID_MASK 0x0000003c /* [37:34] */ | |
130 | #define SQ_INTERRUPT_WORD_ERROR_CTXID1__ENCODING_MASK 0x000000c0 /* [39:38] */ | |
131 | ||
132 | /* | |
133 | * The debugger will send user data(m0) with PRIV=1 to indicate it requires | |
134 | * notification from the KFD with the following queue id (DOORBELL_ID) and | |
135 | * trap code (TRAP_CODE). | |
136 | */ | |
137 | #define KFD_CTXID0_TRAP_CODE_SHIFT 10 | |
138 | #define KFD_CTXID0_TRAP_CODE_MASK 0xfffc00 | |
139 | #define KFD_CTXID0_CP_BAD_OP_ECODE_MASK 0x3ffffff | |
140 | #define KFD_CTXID0_DOORBELL_ID_MASK 0x0003ff | |
141 | ||
142 | #define KFD_CTXID0_TRAP_CODE(ctxid0) (((ctxid0) & \ | |
143 | KFD_CTXID0_TRAP_CODE_MASK) >> \ | |
144 | KFD_CTXID0_TRAP_CODE_SHIFT) | |
145 | #define KFD_CTXID0_CP_BAD_OP_ECODE(ctxid0) (((ctxid0) & \ | |
146 | KFD_CTXID0_CP_BAD_OP_ECODE_MASK) >> \ | |
147 | KFD_CTXID0_TRAP_CODE_SHIFT) | |
148 | #define KFD_CTXID0_DOORBELL_ID(ctxid0) ((ctxid0) & \ | |
149 | KFD_CTXID0_DOORBELL_ID_MASK) | |
150 | ||
151 | static void print_sq_intr_info_auto(uint32_t context_id0, uint32_t context_id1) | |
152 | { | |
37fb8791 | 153 | pr_debug_ratelimited( |
cc009e61 MJ |
154 | "sq_intr: auto, ttrace %d, wlt %d, ttrace_buf_full %d, reg_tms %d, cmd_tms %d, host_cmd_ovf %d, host_reg_ovf %d, immed_ovf %d, ttrace_utc_err %d\n", |
155 | REG_GET_FIELD(context_id0, SQ_INTERRUPT_WORD_AUTO_CTXID0, THREAD_TRACE), | |
156 | REG_GET_FIELD(context_id0, SQ_INTERRUPT_WORD_AUTO_CTXID0, WLT), | |
157 | REG_GET_FIELD(context_id0, SQ_INTERRUPT_WORD_AUTO_CTXID0, THREAD_TRACE_BUF_FULL), | |
158 | REG_GET_FIELD(context_id0, SQ_INTERRUPT_WORD_AUTO_CTXID0, REG_TIMESTAMP), | |
159 | REG_GET_FIELD(context_id0, SQ_INTERRUPT_WORD_AUTO_CTXID0, CMD_TIMESTAMP), | |
160 | REG_GET_FIELD(context_id0, SQ_INTERRUPT_WORD_AUTO_CTXID0, HOST_CMD_OVERFLOW), | |
161 | REG_GET_FIELD(context_id0, SQ_INTERRUPT_WORD_AUTO_CTXID0, HOST_REG_OVERFLOW), | |
162 | REG_GET_FIELD(context_id0, SQ_INTERRUPT_WORD_AUTO_CTXID0, IMMED_OVERFLOW), | |
163 | REG_GET_FIELD(context_id0, SQ_INTERRUPT_WORD_AUTO_CTXID0, THREAD_TRACE_UTC_ERROR)); | |
164 | } | |
165 | ||
166 | static void print_sq_intr_info_inst(uint32_t context_id0, uint32_t context_id1) | |
167 | { | |
37fb8791 | 168 | pr_debug_ratelimited( |
cc009e61 MJ |
169 | "sq_intr: inst, data 0x%08x, sh %d, priv %d, wave_id %d, simd_id %d, wgp_id %d\n", |
170 | REG_GET_FIELD(context_id0, SQ_INTERRUPT_WORD_WAVE_CTXID0, DATA), | |
171 | REG_GET_FIELD(context_id0, SQ_INTERRUPT_WORD_WAVE_CTXID0, SH_ID), | |
172 | REG_GET_FIELD(context_id0, SQ_INTERRUPT_WORD_WAVE_CTXID0, PRIV), | |
173 | REG_GET_FIELD(context_id0, SQ_INTERRUPT_WORD_WAVE_CTXID0, WAVE_ID), | |
174 | REG_GET_FIELD(context_id1, SQ_INTERRUPT_WORD_WAVE_CTXID1, SIMD_ID), | |
175 | REG_GET_FIELD(context_id1, SQ_INTERRUPT_WORD_WAVE_CTXID1, WGP_ID)); | |
176 | } | |
177 | ||
178 | static void print_sq_intr_info_error(uint32_t context_id0, uint32_t context_id1) | |
179 | { | |
37fb8791 | 180 | pr_warn_ratelimited( |
cc009e61 MJ |
181 | "sq_intr: error, detail 0x%08x, type %d, sh %d, priv %d, wave_id %d, simd_id %d, wgp_id %d\n", |
182 | REG_GET_FIELD(context_id0, SQ_INTERRUPT_WORD_ERROR_CTXID0, DETAIL), | |
183 | REG_GET_FIELD(context_id0, SQ_INTERRUPT_WORD_ERROR_CTXID0, TYPE), | |
184 | REG_GET_FIELD(context_id0, SQ_INTERRUPT_WORD_ERROR_CTXID0, SH_ID), | |
185 | REG_GET_FIELD(context_id0, SQ_INTERRUPT_WORD_ERROR_CTXID0, PRIV), | |
186 | REG_GET_FIELD(context_id0, SQ_INTERRUPT_WORD_ERROR_CTXID0, WAVE_ID), | |
187 | REG_GET_FIELD(context_id0, SQ_INTERRUPT_WORD_ERROR_CTXID1, SIMD_ID), | |
188 | REG_GET_FIELD(context_id0, SQ_INTERRUPT_WORD_ERROR_CTXID1, WGP_ID)); | |
189 | } | |
190 | ||
8dc1db31 | 191 | static void event_interrupt_poison_consumption_v11(struct kfd_node *dev, |
cc009e61 MJ |
192 | uint16_t pasid, uint16_t source_id) |
193 | { | |
ed1e1e42 | 194 | enum amdgpu_ras_block block = 0; |
cc009e61 MJ |
195 | int ret = -EINVAL; |
196 | struct kfd_process *p = kfd_lookup_process_by_pasid(pasid); | |
197 | ||
198 | if (!p) | |
199 | return; | |
200 | ||
201 | /* all queues of a process will be unmapped in one time */ | |
202 | if (atomic_read(&p->poison)) { | |
203 | kfd_unref_process(p); | |
204 | return; | |
205 | } | |
206 | ||
207 | atomic_set(&p->poison, 1); | |
208 | kfd_unref_process(p); | |
209 | ||
210 | switch (source_id) { | |
211 | case SOC15_INTSRC_SQ_INTERRUPT_MSG: | |
212 | if (dev->dqm->ops.reset_queues) | |
213 | ret = dev->dqm->ops.reset_queues(dev->dqm, pasid); | |
ed1e1e42 | 214 | block = AMDGPU_RAS_BLOCK__GFX; |
cc009e61 MJ |
215 | break; |
216 | case SOC21_INTSRC_SDMA_ECC: | |
217 | default: | |
ed1e1e42 | 218 | block = AMDGPU_RAS_BLOCK__GFX; |
cc009e61 MJ |
219 | break; |
220 | } | |
221 | ||
222 | kfd_signal_poison_consumed_event(dev, pasid); | |
223 | ||
224 | /* resetting queue passes, do page retirement without gpu reset | |
225 | resetting queue fails, fallback to gpu reset solution */ | |
226 | if (!ret) | |
ed1e1e42 | 227 | amdgpu_amdkfd_ras_poison_consumption_handler(dev->adev, block, false); |
cc009e61 | 228 | else |
ed1e1e42 | 229 | amdgpu_amdkfd_ras_poison_consumption_handler(dev->adev, block, true); |
cc009e61 MJ |
230 | } |
231 | ||
8dc1db31 | 232 | static bool event_interrupt_isr_v11(struct kfd_node *dev, |
cc009e61 MJ |
233 | const uint32_t *ih_ring_entry, |
234 | uint32_t *patched_ihre, | |
235 | bool *patched_flag) | |
236 | { | |
237 | uint16_t source_id, client_id, pasid, vmid; | |
238 | const uint32_t *data = ih_ring_entry; | |
239 | uint32_t context_id0; | |
240 | ||
241 | source_id = SOC15_SOURCE_ID_FROM_IH_ENTRY(ih_ring_entry); | |
242 | client_id = SOC15_CLIENT_ID_FROM_IH_ENTRY(ih_ring_entry); | |
243 | /* Only handle interrupts from KFD VMIDs */ | |
244 | vmid = SOC15_VMID_FROM_IH_ENTRY(ih_ring_entry); | |
12fb1ad7 | 245 | if (!KFD_IRQ_IS_FENCE(client_id, source_id) && |
cc009e61 MJ |
246 | (vmid < dev->vm_info.first_vmid_kfd || |
247 | vmid > dev->vm_info.last_vmid_kfd)) | |
594a1d0f | 248 | return false; |
cc009e61 MJ |
249 | |
250 | pasid = SOC15_PASID_FROM_IH_ENTRY(ih_ring_entry); | |
251 | context_id0 = SOC15_CONTEXT_ID0_FROM_IH_ENTRY(ih_ring_entry); | |
252 | ||
253 | if ((source_id == SOC15_INTSRC_CP_END_OF_PIPE) && | |
254 | (context_id0 & AMDGPU_FENCE_MES_QUEUE_FLAG)) | |
594a1d0f | 255 | return false; |
cc009e61 MJ |
256 | |
257 | pr_debug("client id 0x%x, source id %d, vmid %d, pasid 0x%x. raw data:\n", | |
258 | client_id, source_id, vmid, pasid); | |
259 | pr_debug("%8X, %8X, %8X, %8X, %8X, %8X, %8X, %8X.\n", | |
260 | data[0], data[1], data[2], data[3], | |
261 | data[4], data[5], data[6], data[7]); | |
262 | ||
263 | /* If there is no valid PASID, it's likely a bug */ | |
264 | if (WARN_ONCE(pasid == 0, "Bug: No PASID in KFD interrupt")) | |
594a1d0f | 265 | return false; |
cc009e61 MJ |
266 | |
267 | /* Interrupt types we care about: various signals and faults. | |
268 | * They will be forwarded to a work queue (see below). | |
269 | */ | |
270 | return source_id == SOC15_INTSRC_CP_END_OF_PIPE || | |
271 | source_id == SOC15_INTSRC_SQ_INTERRUPT_MSG || | |
272 | source_id == SOC15_INTSRC_CP_BAD_OPCODE || | |
273 | source_id == SOC21_INTSRC_SDMA_TRAP || | |
12fb1ad7 | 274 | KFD_IRQ_IS_FENCE(client_id, source_id) || |
3055e5d1 GS |
275 | (((client_id == SOC21_IH_CLIENTID_VMC) || |
276 | ((client_id == SOC21_IH_CLIENTID_GFX) && | |
277 | (source_id == UTCL2_1_0__SRCID__FAULT))) && | |
278 | !amdgpu_no_queue_eviction_on_vm_fault); | |
cc009e61 MJ |
279 | } |
280 | ||
8dc1db31 | 281 | static void event_interrupt_wq_v11(struct kfd_node *dev, |
cc009e61 MJ |
282 | const uint32_t *ih_ring_entry) |
283 | { | |
284 | uint16_t source_id, client_id, ring_id, pasid, vmid; | |
285 | uint32_t context_id0, context_id1; | |
12fb1ad7 | 286 | uint8_t sq_int_enc, sq_int_priv, sq_int_errtype; |
cc009e61 MJ |
287 | struct kfd_vm_fault_info info = {0}; |
288 | struct kfd_hsa_memory_exception_data exception_data; | |
289 | ||
290 | source_id = SOC15_SOURCE_ID_FROM_IH_ENTRY(ih_ring_entry); | |
291 | client_id = SOC15_CLIENT_ID_FROM_IH_ENTRY(ih_ring_entry); | |
292 | ring_id = SOC15_RING_ID_FROM_IH_ENTRY(ih_ring_entry); | |
293 | pasid = SOC15_PASID_FROM_IH_ENTRY(ih_ring_entry); | |
294 | vmid = SOC15_VMID_FROM_IH_ENTRY(ih_ring_entry); | |
295 | context_id0 = SOC15_CONTEXT_ID0_FROM_IH_ENTRY(ih_ring_entry); | |
296 | context_id1 = SOC15_CONTEXT_ID1_FROM_IH_ENTRY(ih_ring_entry); | |
297 | ||
298 | /* VMC, UTCL2 */ | |
299 | if (client_id == SOC21_IH_CLIENTID_VMC || | |
300 | ((client_id == SOC21_IH_CLIENTID_GFX) && | |
301 | (source_id == UTCL2_1_0__SRCID__FAULT))) { | |
302 | ||
303 | info.vmid = vmid; | |
304 | info.mc_id = client_id; | |
305 | info.page_addr = ih_ring_entry[4] | | |
306 | (uint64_t)(ih_ring_entry[5] & 0xf) << 32; | |
307 | info.prot_valid = ring_id & 0x08; | |
308 | info.prot_read = ring_id & 0x10; | |
309 | info.prot_write = ring_id & 0x20; | |
310 | ||
311 | memset(&exception_data, 0, sizeof(exception_data)); | |
312 | exception_data.gpu_id = dev->id; | |
313 | exception_data.va = (info.page_addr) << PAGE_SHIFT; | |
314 | exception_data.failure.NotPresent = info.prot_valid ? 1 : 0; | |
315 | exception_data.failure.NoExecute = info.prot_exec ? 1 : 0; | |
316 | exception_data.failure.ReadOnly = info.prot_write ? 1 : 0; | |
317 | exception_data.failure.imprecise = 0; | |
318 | ||
12fb1ad7 | 319 | kfd_set_dbg_ev_from_interrupt(dev, pasid, -1, |
cc009e61 | 320 | KFD_EC_MASK(EC_DEVICE_MEMORY_VIOLATION), |
12fb1ad7 | 321 | &exception_data, sizeof(exception_data)); |
cc009e61 MJ |
322 | kfd_smi_event_update_vmfault(dev, pasid); |
323 | ||
324 | /* GRBM, SDMA, SE, PMM */ | |
325 | } else if (client_id == SOC21_IH_CLIENTID_GRBM_CP || | |
326 | client_id == SOC21_IH_CLIENTID_GFX) { | |
327 | ||
328 | /* CP */ | |
329 | if (source_id == SOC15_INTSRC_CP_END_OF_PIPE) | |
330 | kfd_signal_event_interrupt(pasid, context_id0, 32); | |
0cac183b JK |
331 | else if (source_id == SOC15_INTSRC_CP_BAD_OPCODE && |
332 | KFD_DBG_EC_TYPE_IS_PACKET(KFD_CTXID0_CP_BAD_OP_ECODE(context_id0))) | |
cc009e61 MJ |
333 | kfd_set_dbg_ev_from_interrupt(dev, pasid, |
334 | KFD_CTXID0_DOORBELL_ID(context_id0), | |
335 | KFD_EC_MASK(KFD_CTXID0_CP_BAD_OP_ECODE(context_id0)), | |
12fb1ad7 | 336 | NULL, 0); |
cc009e61 MJ |
337 | |
338 | /* SDMA */ | |
339 | else if (source_id == SOC21_INTSRC_SDMA_TRAP) | |
340 | kfd_signal_event_interrupt(pasid, context_id0 & 0xfffffff, 28); | |
341 | else if (source_id == SOC21_INTSRC_SDMA_ECC) { | |
342 | event_interrupt_poison_consumption_v11(dev, pasid, source_id); | |
343 | return; | |
344 | } | |
345 | ||
346 | /* SQ */ | |
347 | else if (source_id == SOC15_INTSRC_SQ_INTERRUPT_MSG) { | |
348 | sq_int_enc = REG_GET_FIELD(context_id1, | |
349 | SQ_INTERRUPT_WORD_WAVE_CTXID1, ENCODING); | |
350 | switch (sq_int_enc) { | |
351 | case SQ_INTERRUPT_WORD_ENCODING_AUTO: | |
352 | print_sq_intr_info_auto(context_id0, context_id1); | |
353 | break; | |
354 | case SQ_INTERRUPT_WORD_ENCODING_INST: | |
355 | print_sq_intr_info_inst(context_id0, context_id1); | |
12fb1ad7 JK |
356 | sq_int_priv = REG_GET_FIELD(context_id0, |
357 | SQ_INTERRUPT_WORD_WAVE_CTXID0, PRIV); | |
358 | if (sq_int_priv && (kfd_set_dbg_ev_from_interrupt(dev, pasid, | |
359 | KFD_CTXID0_DOORBELL_ID(context_id0), | |
360 | KFD_CTXID0_TRAP_CODE(context_id0), | |
361 | NULL, 0))) | |
362 | return; | |
cc009e61 MJ |
363 | break; |
364 | case SQ_INTERRUPT_WORD_ENCODING_ERROR: | |
365 | print_sq_intr_info_error(context_id0, context_id1); | |
366 | sq_int_errtype = REG_GET_FIELD(context_id0, | |
367 | SQ_INTERRUPT_WORD_ERROR_CTXID0, TYPE); | |
368 | if (sq_int_errtype != SQ_INTERRUPT_ERROR_TYPE_ILLEGAL_INST && | |
369 | sq_int_errtype != SQ_INTERRUPT_ERROR_TYPE_MEMVIOL) { | |
370 | event_interrupt_poison_consumption_v11( | |
371 | dev, pasid, source_id); | |
372 | return; | |
373 | } | |
374 | break; | |
375 | default: | |
376 | break; | |
377 | } | |
378 | kfd_signal_event_interrupt(pasid, context_id0 & 0xffffff, 24); | |
379 | } | |
380 | ||
12fb1ad7 JK |
381 | } else if (KFD_IRQ_IS_FENCE(client_id, source_id)) { |
382 | kfd_process_close_interrupt_drain(pasid); | |
cc009e61 MJ |
383 | } |
384 | } | |
385 | ||
386 | const struct kfd_event_interrupt_class event_interrupt_class_v11 = { | |
387 | .interrupt_isr = event_interrupt_isr_v11, | |
388 | .interrupt_wq = event_interrupt_wq_v11, | |
389 | }; |