return 0;
 }
 
-void kfd_event_init_process(struct kfd_process *p)
+int kfd_event_init_process(struct kfd_process *p)
 {
+       int id;
+
        mutex_init(&p->event_mutex);
        idr_init(&p->event_idr);
        p->signal_page = NULL;
-       p->signal_event_count = 0;
+       p->signal_event_count = 1;
+       /* Allocate event ID 0. It is used for a fast path to ignore bogus events
+        * that are sent by the CP without a context ID
+        */
+       id = idr_alloc(&p->event_idr, NULL, 0, 1, GFP_KERNEL);
+       if (id < 0) {
+               idr_destroy(&p->event_idr);
+               mutex_destroy(&p->event_mutex);
+               return id;
+       }
+       return 0;
 }
 
 static void destroy_event(struct kfd_process *p, struct kfd_event *ev)
        uint32_t id;
 
        idr_for_each_entry(&p->event_idr, ev, id)
-               destroy_event(p, ev);
+               if (ev)
+                       destroy_event(p, ev);
        idr_destroy(&p->event_idr);
+       mutex_destroy(&p->event_mutex);
 }
 
 /*
                         * iterate over the signal slots and lookup
                         * only signaled events from the IDR.
                         */
-                       for (id = 0; id < KFD_SIGNAL_EVENT_LIMIT; id++)
+                       for (id = 1; id < KFD_SIGNAL_EVENT_LIMIT; id++)
                                if (READ_ONCE(slots[id]) != UNSIGNALED_EVENT_SLOT) {
                                        ev = lookup_event_by_id(p, id);
                                        set_event_from_interrupt(p, ev);
 
        }
 }
 
+static bool context_id_expected(struct kfd_dev *dev)
+{
+       switch (KFD_GC_VERSION(dev)) {
+       case IP_VERSION(9, 0, 1):
+               return dev->mec_fw_version >= 0x817a;
+       case IP_VERSION(9, 1, 0):
+       case IP_VERSION(9, 2, 1):
+       case IP_VERSION(9, 2, 2):
+       case IP_VERSION(9, 3, 0):
+       case IP_VERSION(9, 4, 0):
+               return dev->mec_fw_version >= 0x17a;
+       default:
+               /* Other GFXv9 and later GPUs always sent valid context IDs
+                * on legitimate events
+                */
+               return KFD_GC_VERSION(dev) >= IP_VERSION(9, 4, 1);
+       }
+}
+
 static bool event_interrupt_isr_v9(struct kfd_dev *dev,
                                        const uint32_t *ih_ring_entry,
                                        uint32_t *patched_ihre,
        if (WARN_ONCE(pasid == 0, "Bug: No PASID in KFD interrupt"))
                return false;
 
+       /* Workaround CP firmware sending bogus signals with 0 context_id.
+        * Those can be safely ignored on hardware and firmware versions that
+        * include a valid context_id on legitimate signals. This avoids the
+        * slow path in kfd_signal_event_interrupt that scans all event slots
+        * for signaled events.
+        */
+       if (source_id == SOC15_INTSRC_CP_END_OF_PIPE) {
+               uint32_t context_id =
+                       SOC15_CONTEXT_ID0_FROM_IH_ENTRY(ih_ring_entry);
+
+               if (context_id == 0 && context_id_expected(dev))
+                       return false;
+       }
+
        /* Interrupt types we care about: various signals and faults.
         * They will be forwarded to a work queue (see below).
         */
 
 
 extern const struct kfd_device_global_init_class device_global_init_class_cik;
 
-void kfd_event_init_process(struct kfd_process *p);
+int kfd_event_init_process(struct kfd_process *p);
 void kfd_event_free_process(struct kfd_process *p);
 int kfd_event_mmap(struct kfd_process *process, struct vm_area_struct *vma);
 int kfd_wait_on_events(struct kfd_process *p,
 
        INIT_DELAYED_WORK(&process->eviction_work, evict_process_worker);
        INIT_DELAYED_WORK(&process->restore_work, restore_process_worker);
        process->last_restore_timestamp = get_jiffies_64();
-       kfd_event_init_process(process);
+       err = kfd_event_init_process(process);
+       if (err)
+               goto err_event_init;
        process->is_32bit_user_mode = in_compat_syscall();
 
        process->pasid = kfd_pasid_alloc();
-       if (process->pasid == 0)
+       if (process->pasid == 0) {
+               err = -ENOSPC;
                goto err_alloc_pasid;
+       }
 
        err = pqm_init(&process->pqm, process);
        if (err != 0)
 err_process_pqm_init:
        kfd_pasid_free(process->pasid);
 err_alloc_pasid:
+       kfd_event_free_process(process);
+err_event_init:
        mutex_destroy(&process->mutex);
        kfree(process);
 err_alloc_process: