drm/amdkfd: Add bad opcode exception handling

Signed-off-by: Alexey Skidanov <alexey.skidanov@gmail.com>
Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com>
This commit is contained in:
Alexey Skidanov 2014-11-25 10:34:31 +02:00 committed by Oded Gabbay
parent 59d3e8be87
commit 930c5ff439
5 changed files with 29 additions and 1 deletions

View file

@ -36,7 +36,8 @@ static bool cik_event_interrupt_isr(struct kfd_dev *dev,
/* Do not process in ISR, just request it to be forwarded to WQ. */ /* Do not process in ISR, just request it to be forwarded to WQ. */
return (pasid != 0) && return (pasid != 0) &&
(ihre->source_id == CIK_INTSRC_CP_END_OF_PIPE || (ihre->source_id == CIK_INTSRC_CP_END_OF_PIPE ||
ihre->source_id == CIK_INTSRC_SQ_INTERRUPT_MSG); ihre->source_id == CIK_INTSRC_SQ_INTERRUPT_MSG ||
ihre->source_id == CIK_INTSRC_CP_BAD_OPCODE);
} }
static void cik_event_interrupt_wq(struct kfd_dev *dev, static void cik_event_interrupt_wq(struct kfd_dev *dev,
@ -55,6 +56,8 @@ static void cik_event_interrupt_wq(struct kfd_dev *dev,
kfd_signal_event_interrupt(pasid, 0, 0); kfd_signal_event_interrupt(pasid, 0, 0);
else if (ihre->source_id == CIK_INTSRC_SQ_INTERRUPT_MSG) else if (ihre->source_id == CIK_INTSRC_SQ_INTERRUPT_MSG)
kfd_signal_event_interrupt(pasid, ihre->data & 0xFF, 8); kfd_signal_event_interrupt(pasid, ihre->data & 0xFF, 8);
else if (ihre->source_id == CIK_INTSRC_CP_BAD_OPCODE)
kfd_signal_hw_exception_event(pasid);
} }
const struct kfd_event_interrupt_class event_interrupt_class_cik = { const struct kfd_event_interrupt_class event_interrupt_class_cik = {

View file

@ -34,6 +34,7 @@ struct cik_ih_ring_entry {
#define CIK_INTSRC_DEQUEUE_COMPLETE 0xC6 #define CIK_INTSRC_DEQUEUE_COMPLETE 0xC6
#define CIK_INTSRC_CP_END_OF_PIPE 0xB5 #define CIK_INTSRC_CP_END_OF_PIPE 0xB5
#define CIK_INTSRC_CP_BAD_OPCODE 0xB7
#define CIK_INTSRC_SQ_INTERRUPT_MSG 0xEF #define CIK_INTSRC_SQ_INTERRUPT_MSG 0xEF
#endif #endif

View file

@ -936,3 +936,24 @@ void kfd_signal_iommu_event(struct kfd_dev *dev, unsigned int pasid,
mutex_unlock(&p->event_mutex); mutex_unlock(&p->event_mutex);
mutex_unlock(&p->mutex); mutex_unlock(&p->mutex);
} }
void kfd_signal_hw_exception_event(unsigned int pasid)
{
/*
* Because we are called from arbitrary context (workqueue) as opposed
* to process context, kfd_process could attempt to exit while we are
* running so the lookup function returns a locked process.
*/
struct kfd_process *p = kfd_lookup_process_by_pasid(pasid);
if (!p)
return; /* Presumably process exited. */
mutex_lock(&p->event_mutex);
/* Lookup events by type and signal them */
lookup_events_by_type_and_signal(p, KFD_EVENT_TYPE_HW_EXCEPTION, NULL);
mutex_unlock(&p->event_mutex);
mutex_unlock(&p->mutex);
}

View file

@ -74,6 +74,7 @@ struct kfd_event {
/* Matching HSA_EVENTTYPE */ /* Matching HSA_EVENTTYPE */
#define KFD_EVENT_TYPE_SIGNAL 0 #define KFD_EVENT_TYPE_SIGNAL 0
#define KFD_EVENT_TYPE_HW_EXCEPTION 3
#define KFD_EVENT_TYPE_DEBUG 5 #define KFD_EVENT_TYPE_DEBUG 5
#define KFD_EVENT_TYPE_MEMORY 8 #define KFD_EVENT_TYPE_MEMORY 8

View file

@ -682,6 +682,7 @@ phys_addr_t kfd_get_process_doorbells(struct kfd_dev *dev,
/* Events */ /* Events */
extern const struct kfd_event_interrupt_class event_interrupt_class_cik; extern const struct kfd_event_interrupt_class event_interrupt_class_cik;
extern const struct kfd_device_global_init_class device_global_init_class_cik;
enum kfd_event_wait_result { enum kfd_event_wait_result {
KFD_WAIT_COMPLETE, KFD_WAIT_COMPLETE,
@ -701,6 +702,7 @@ void kfd_signal_event_interrupt(unsigned int pasid, uint32_t partial_id,
void kfd_signal_iommu_event(struct kfd_dev *dev, void kfd_signal_iommu_event(struct kfd_dev *dev,
unsigned int pasid, unsigned long address, unsigned int pasid, unsigned long address,
bool is_write_requested, bool is_execute_requested); bool is_write_requested, bool is_execute_requested);
void kfd_signal_hw_exception_event(unsigned int pasid);
int kfd_set_event(struct kfd_process *p, uint32_t event_id); int kfd_set_event(struct kfd_process *p, uint32_t event_id);
int kfd_reset_event(struct kfd_process *p, uint32_t event_id); int kfd_reset_event(struct kfd_process *p, uint32_t event_id);
int kfd_event_create(struct file *devkfd, struct kfd_process *p, int kfd_event_create(struct file *devkfd, struct kfd_process *p,