drm/amdkfd: Add interrupt handling module
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / drm / amd / amdkfd / kfd_device.c
index ca7f2d3af2ff048301864158b4df492b5e43eb1e..13c30a0996842c8c994d0fc189c332dfef9917e9 100644 (file)
@@ -235,6 +235,13 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd,
                goto kfd_topology_add_device_error;
        }
 
+       if (kfd_interrupt_init(kfd)) {
+               dev_err(kfd_device,
+                       "Error initializing interrupts for device (%x:%x)\n",
+                       kfd->pdev->vendor, kfd->pdev->device);
+               goto kfd_interrupt_error;
+       }
+
        if (!device_iommu_pasid_init(kfd)) {
                dev_err(kfd_device,
                        "Error initializing iommuv2 for device (%x:%x)\n",
@@ -273,6 +280,8 @@ dqm_start_error:
 device_queue_manager_error:
        amd_iommu_free_device(kfd->pdev);
 device_iommu_pasid_error:
+       kfd_interrupt_exit(kfd);
+kfd_interrupt_error:
        kfd_topology_remove_device(kfd);
 kfd_topology_add_device_error:
        kfd_gtt_sa_fini(kfd);
@@ -290,6 +299,7 @@ void kgd2kfd_device_exit(struct kfd_dev *kfd)
        if (kfd->init_complete) {
                device_queue_manager_uninit(kfd->dqm);
                amd_iommu_free_device(kfd->pdev);
+               kfd_interrupt_exit(kfd);
                kfd_topology_remove_device(kfd);
                kfd_gtt_sa_fini(kfd);
                kfd->kfd2kgd->free_gtt_mem(kfd->kgd, kfd->gtt_mem);
@@ -333,7 +343,17 @@ int kgd2kfd_resume(struct kfd_dev *kfd)
 /* This is called directly from KGD at ISR. */
 void kgd2kfd_interrupt(struct kfd_dev *kfd, const void *ih_ring_entry)
 {
-       /* Process interrupts / schedule work as necessary */
+       if (!kfd->init_complete)
+               return;
+
+       spin_lock(&kfd->interrupt_lock);
+
+       if (kfd->interrupts_active
+           && interrupt_is_wanted(kfd, ih_ring_entry)
+           && enqueue_ih_ring_entry(kfd, ih_ring_entry))
+               schedule_work(&kfd->interrupt_work);
+
+       spin_unlock(&kfd->interrupt_lock);
 }
 
 static int kfd_gtt_sa_init(struct kfd_dev *kfd, unsigned int buf_size,