diff options
author | Felix Kuehling <Felix.Kuehling@amd.com> | 2018-05-01 17:56:12 -0400 |
---|---|---|
committer | Oded Gabbay <oded.gabbay@gmail.com> | 2018-05-01 17:56:12 -0400 |
commit | c129db1206bd11ab0531a4d91a455a0809acae0e (patch) | |
tree | fd965f83948f9dfea0baf899d6e83fb0a90864e9 | |
parent | 2533f0741e5f7259393d7edecb4bca3106c583c2 (diff) |
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).
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>
Reviewed-by: Oded Gabbay <oded.gabbay@gmail.com>
Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com>
-rw-r--r-- | drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c | 20 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c | 40 |
2 files changed, 39 insertions, 21 deletions
diff --git a/drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c b/drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c index 3d5ccb3755d4..49df6c791cfc 100644 --- a/drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c +++ b/drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c | |||
@@ -27,18 +27,28 @@ | |||
27 | static bool cik_event_interrupt_isr(struct kfd_dev *dev, | 27 | static bool cik_event_interrupt_isr(struct kfd_dev *dev, |
28 | const uint32_t *ih_ring_entry) | 28 | const uint32_t *ih_ring_entry) |
29 | { | 29 | { |
30 | unsigned int pasid; | ||
31 | const struct cik_ih_ring_entry *ihre = | 30 | const struct cik_ih_ring_entry *ihre = |
32 | (const struct cik_ih_ring_entry *)ih_ring_entry; | 31 | (const struct cik_ih_ring_entry *)ih_ring_entry; |
32 | unsigned int vmid, pasid; | ||
33 | |||
34 | /* Only handle interrupts from KFD VMIDs */ | ||
35 | vmid = (ihre->ring_id & 0x0000ff00) >> 8; | ||
36 | if (vmid < dev->vm_info.first_vmid_kfd || | ||
37 | vmid > dev->vm_info.last_vmid_kfd) | ||
38 | return 0; | ||
33 | 39 | ||
40 | /* If there is no valid PASID, it's likely a firmware bug */ | ||
34 | pasid = (ihre->ring_id & 0xffff0000) >> 16; | 41 | pasid = (ihre->ring_id & 0xffff0000) >> 16; |
42 | if (WARN_ONCE(pasid == 0, "FW bug: No PASID in KFD interrupt")) | ||
43 | return 0; | ||
35 | 44 | ||
36 | /* Do not process in ISR, just request it to be forwarded to WQ. */ | 45 | /* Interrupt types we care about: various signals and faults. |
37 | return (pasid != 0) && | 46 | * They will be forwarded to a work queue (see below). |
38 | (ihre->source_id == CIK_INTSRC_CP_END_OF_PIPE || | 47 | */ |
48 | return ihre->source_id == CIK_INTSRC_CP_END_OF_PIPE || | ||
39 | ihre->source_id == CIK_INTSRC_SDMA_TRAP || | 49 | ihre->source_id == CIK_INTSRC_SDMA_TRAP || |
40 | ihre->source_id == CIK_INTSRC_SQ_INTERRUPT_MSG || | 50 | ihre->source_id == CIK_INTSRC_SQ_INTERRUPT_MSG || |
41 | ihre->source_id == CIK_INTSRC_CP_BAD_OPCODE); | 51 | ihre->source_id == CIK_INTSRC_CP_BAD_OPCODE; |
42 | } | 52 | } |
43 | 53 | ||
44 | static void cik_event_interrupt_wq(struct kfd_dev *dev, | 54 | 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 39d41155581f..37029baa3346 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c | |||
@@ -29,27 +29,35 @@ static bool event_interrupt_isr_v9(struct kfd_dev *dev, | |||
29 | const uint32_t *ih_ring_entry) | 29 | const uint32_t *ih_ring_entry) |
30 | { | 30 | { |
31 | uint16_t source_id, client_id, pasid, vmid; | 31 | uint16_t source_id, client_id, pasid, vmid; |
32 | const uint32_t *data = ih_ring_entry; | ||
32 | 33 | ||
33 | source_id = SOC15_SOURCE_ID_FROM_IH_ENTRY(ih_ring_entry); | 34 | /* Only handle interrupts from KFD VMIDs */ |
34 | client_id = SOC15_CLIENT_ID_FROM_IH_ENTRY(ih_ring_entry); | ||
35 | pasid = SOC15_PASID_FROM_IH_ENTRY(ih_ring_entry); | ||
36 | vmid = SOC15_VMID_FROM_IH_ENTRY(ih_ring_entry); | 35 | vmid = SOC15_VMID_FROM_IH_ENTRY(ih_ring_entry); |
36 | if (vmid < dev->vm_info.first_vmid_kfd || | ||
37 | vmid > dev->vm_info.last_vmid_kfd) | ||
38 | return 0; | ||
39 | |||
40 | /* If there is no valid PASID, it's likely a firmware bug */ | ||
41 | pasid = SOC15_PASID_FROM_IH_ENTRY(ih_ring_entry); | ||
42 | if (WARN_ONCE(pasid == 0, "FW bug: No PASID in KFD interrupt")) | ||
43 | return 0; | ||
37 | 44 | ||
38 | if (pasid) { | 45 | source_id = SOC15_SOURCE_ID_FROM_IH_ENTRY(ih_ring_entry); |
39 | const uint32_t *data = ih_ring_entry; | 46 | client_id = SOC15_CLIENT_ID_FROM_IH_ENTRY(ih_ring_entry); |
40 | 47 | ||
41 | pr_debug("client id 0x%x, source id %d, pasid 0x%x. raw data:\n", | 48 | pr_debug("client id 0x%x, source id %d, pasid 0x%x. raw data:\n", |
42 | client_id, source_id, pasid); | 49 | client_id, source_id, pasid); |
43 | pr_debug("%8X, %8X, %8X, %8X, %8X, %8X, %8X, %8X.\n", | 50 | pr_debug("%8X, %8X, %8X, %8X, %8X, %8X, %8X, %8X.\n", |
44 | data[0], data[1], data[2], data[3], | 51 | data[0], data[1], data[2], data[3], |
45 | data[4], data[5], data[6], data[7]); | 52 | data[4], data[5], data[6], data[7]); |
46 | } | ||
47 | 53 | ||
48 | return (pasid != 0) && | 54 | /* Interrupt types we care about: various signals and faults. |
49 | (source_id == SOC15_INTSRC_CP_END_OF_PIPE || | 55 | * They will be forwarded to a work queue (see below). |
50 | source_id == SOC15_INTSRC_SDMA_TRAP || | 56 | */ |
51 | source_id == SOC15_INTSRC_SQ_INTERRUPT_MSG || | 57 | return source_id == SOC15_INTSRC_CP_END_OF_PIPE || |
52 | source_id == SOC15_INTSRC_CP_BAD_OPCODE); | 58 | source_id == SOC15_INTSRC_SDMA_TRAP || |
59 | source_id == SOC15_INTSRC_SQ_INTERRUPT_MSG || | ||
60 | source_id == SOC15_INTSRC_CP_BAD_OPCODE; | ||
53 | } | 61 | } |
54 | 62 | ||
55 | static void event_interrupt_wq_v9(struct kfd_dev *dev, | 63 | static void event_interrupt_wq_v9(struct kfd_dev *dev, |