1ca750681SFelix Kuehling /*
2ca750681SFelix Kuehling  * Copyright 2016-2018 Advanced Micro Devices, Inc.
3ca750681SFelix Kuehling  *
4ca750681SFelix Kuehling  * Permission is hereby granted, free of charge, to any person obtaining a
5ca750681SFelix Kuehling  * copy of this software and associated documentation files (the "Software"),
6ca750681SFelix Kuehling  * to deal in the Software without restriction, including without limitation
7ca750681SFelix Kuehling  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8ca750681SFelix Kuehling  * and/or sell copies of the Software, and to permit persons to whom the
9ca750681SFelix Kuehling  * Software is furnished to do so, subject to the following conditions:
10ca750681SFelix Kuehling  *
11ca750681SFelix Kuehling  * The above copyright notice and this permission notice shall be included in
12ca750681SFelix Kuehling  * all copies or substantial portions of the Software.
13ca750681SFelix Kuehling  *
14ca750681SFelix Kuehling  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15ca750681SFelix Kuehling  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16ca750681SFelix Kuehling  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17ca750681SFelix Kuehling  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18ca750681SFelix Kuehling  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19ca750681SFelix Kuehling  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20ca750681SFelix Kuehling  * OTHER DEALINGS IN THE SOFTWARE.
21ca750681SFelix Kuehling  */
22ca750681SFelix Kuehling 
23ca750681SFelix Kuehling #include "kfd_priv.h"
24ca750681SFelix Kuehling #include "kfd_events.h"
25ca750681SFelix Kuehling #include "soc15_int.h"
26ca750681SFelix Kuehling 
27ca750681SFelix Kuehling 
28ca750681SFelix Kuehling static bool event_interrupt_isr_v9(struct kfd_dev *dev,
2958e69886SLan Xiao 					const uint32_t *ih_ring_entry,
3058e69886SLan Xiao 					uint32_t *patched_ihre,
3158e69886SLan Xiao 					bool *patched_flag)
32ca750681SFelix Kuehling {
33ca750681SFelix Kuehling 	uint16_t source_id, client_id, pasid, vmid;
34c129db12SFelix Kuehling 	const uint32_t *data = ih_ring_entry;
35c129db12SFelix Kuehling 
36c129db12SFelix Kuehling 	/* Only handle interrupts from KFD VMIDs */
37c129db12SFelix Kuehling 	vmid = SOC15_VMID_FROM_IH_ENTRY(ih_ring_entry);
38c129db12SFelix Kuehling 	if (vmid < dev->vm_info.first_vmid_kfd ||
39c129db12SFelix Kuehling 	    vmid > dev->vm_info.last_vmid_kfd)
40c129db12SFelix Kuehling 		return 0;
41c129db12SFelix Kuehling 
42ca750681SFelix Kuehling 	source_id = SOC15_SOURCE_ID_FROM_IH_ENTRY(ih_ring_entry);
43ca750681SFelix Kuehling 	client_id = SOC15_CLIENT_ID_FROM_IH_ENTRY(ih_ring_entry);
4400557f41SYong Zhao 	pasid = SOC15_PASID_FROM_IH_ENTRY(ih_ring_entry);
45ca750681SFelix Kuehling 
4600557f41SYong Zhao 	pr_debug("client id 0x%x, source id %d, vmid %d, pasid 0x%x. raw data:\n",
4700557f41SYong Zhao 		 client_id, source_id, vmid, pasid);
48ca750681SFelix Kuehling 	pr_debug("%8X, %8X, %8X, %8X, %8X, %8X, %8X, %8X.\n",
49ca750681SFelix Kuehling 		 data[0], data[1], data[2], data[3],
50ca750681SFelix Kuehling 		 data[4], data[5], data[6], data[7]);
51ca750681SFelix Kuehling 
5200557f41SYong Zhao 	/* If there is no valid PASID, it's likely a firmware bug */
5300557f41SYong Zhao 	if (WARN_ONCE(pasid == 0, "FW bug: No PASID in KFD interrupt"))
5400557f41SYong Zhao 		return 0;
5500557f41SYong Zhao 
56c129db12SFelix Kuehling 	/* Interrupt types we care about: various signals and faults.
57c129db12SFelix Kuehling 	 * They will be forwarded to a work queue (see below).
58c129db12SFelix Kuehling 	 */
59c129db12SFelix Kuehling 	return source_id == SOC15_INTSRC_CP_END_OF_PIPE ||
60ca750681SFelix Kuehling 		source_id == SOC15_INTSRC_SDMA_TRAP ||
61ca750681SFelix Kuehling 		source_id == SOC15_INTSRC_SQ_INTERRUPT_MSG ||
622640c3faSshaoyunl 		source_id == SOC15_INTSRC_CP_BAD_OPCODE ||
632640c3faSshaoyunl 		client_id == SOC15_IH_CLIENTID_VMC ||
642640c3faSshaoyunl 		client_id == SOC15_IH_CLIENTID_UTCL2;
65ca750681SFelix Kuehling }
66ca750681SFelix Kuehling 
67ca750681SFelix Kuehling static void event_interrupt_wq_v9(struct kfd_dev *dev,
68ca750681SFelix Kuehling 					const uint32_t *ih_ring_entry)
69ca750681SFelix Kuehling {
70ca750681SFelix Kuehling 	uint16_t source_id, client_id, pasid, vmid;
71ca750681SFelix Kuehling 	uint32_t context_id;
72ca750681SFelix Kuehling 
73ca750681SFelix Kuehling 	source_id = SOC15_SOURCE_ID_FROM_IH_ENTRY(ih_ring_entry);
74ca750681SFelix Kuehling 	client_id = SOC15_CLIENT_ID_FROM_IH_ENTRY(ih_ring_entry);
75ca750681SFelix Kuehling 	pasid = SOC15_PASID_FROM_IH_ENTRY(ih_ring_entry);
76ca750681SFelix Kuehling 	vmid = SOC15_VMID_FROM_IH_ENTRY(ih_ring_entry);
77ca750681SFelix Kuehling 	context_id = SOC15_CONTEXT_ID0_FROM_IH_ENTRY(ih_ring_entry);
78ca750681SFelix Kuehling 
79ca750681SFelix Kuehling 	if (source_id == SOC15_INTSRC_CP_END_OF_PIPE)
80ca750681SFelix Kuehling 		kfd_signal_event_interrupt(pasid, context_id, 32);
81ca750681SFelix Kuehling 	else if (source_id == SOC15_INTSRC_SDMA_TRAP)
82ca750681SFelix Kuehling 		kfd_signal_event_interrupt(pasid, context_id & 0xfffffff, 28);
83ca750681SFelix Kuehling 	else if (source_id == SOC15_INTSRC_SQ_INTERRUPT_MSG)
84ca750681SFelix Kuehling 		kfd_signal_event_interrupt(pasid, context_id & 0xffffff, 24);
85ca750681SFelix Kuehling 	else if (source_id == SOC15_INTSRC_CP_BAD_OPCODE)
86ca750681SFelix Kuehling 		kfd_signal_hw_exception_event(pasid);
87ca750681SFelix Kuehling 	else if (client_id == SOC15_IH_CLIENTID_VMC ||
88ca750681SFelix Kuehling 		 client_id == SOC15_IH_CLIENTID_UTCL2) {
892640c3faSshaoyunl 		struct kfd_vm_fault_info info = {0};
902640c3faSshaoyunl 		uint16_t ring_id = SOC15_RING_ID_FROM_IH_ENTRY(ih_ring_entry);
912640c3faSshaoyunl 
922640c3faSshaoyunl 		info.vmid = vmid;
932640c3faSshaoyunl 		info.mc_id = client_id;
942640c3faSshaoyunl 		info.page_addr = ih_ring_entry[4] |
952640c3faSshaoyunl 			(uint64_t)(ih_ring_entry[5] & 0xf) << 32;
962640c3faSshaoyunl 		info.prot_valid = ring_id & 0x08;
972640c3faSshaoyunl 		info.prot_read  = ring_id & 0x10;
982640c3faSshaoyunl 		info.prot_write = ring_id & 0x20;
992640c3faSshaoyunl 
1002640c3faSshaoyunl 		kfd_process_vm_fault(dev->dqm, pasid);
1012640c3faSshaoyunl 		kfd_signal_vm_fault_event(dev, pasid, &info);
102ca750681SFelix Kuehling 	}
103ca750681SFelix Kuehling }
104ca750681SFelix Kuehling 
105ca750681SFelix Kuehling const struct kfd_event_interrupt_class event_interrupt_class_v9 = {
106ca750681SFelix Kuehling 	.interrupt_isr = event_interrupt_isr_v9,
107ca750681SFelix Kuehling 	.interrupt_wq = event_interrupt_wq_v9,
108ca750681SFelix Kuehling };
109