diff options
Diffstat (limited to 'drivers/gpu/drm/amd/amdkfd/kfd_device.c')
-rw-r--r-- | drivers/gpu/drm/amd/amdkfd/kfd_device.c | 122 |
1 files changed, 115 insertions, 7 deletions
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c index 7ee6cec2c060..1b048715ab8a 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c @@ -30,7 +30,13 @@ #include "kfd_iommu.h" #define MQD_SIZE_ALIGNED 768 -static atomic_t kfd_device_suspended = ATOMIC_INIT(0); + +/* + * kfd_locked is used to lock the kfd driver during suspend or reset + * once locked, kfd driver will stop any further GPU execution. + * create process (open) will return -EAGAIN. + */ +static atomic_t kfd_locked = ATOMIC_INIT(0); #ifdef KFD_SUPPORT_IOMMU_V2 static const struct kfd_device_info kaveri_device_info = { @@ -46,6 +52,7 @@ static const struct kfd_device_info kaveri_device_info = { .supports_cwsr = false, .needs_iommu_device = true, .needs_pci_atomics = false, + .num_sdma_engines = 2, }; static const struct kfd_device_info carrizo_device_info = { @@ -61,6 +68,22 @@ static const struct kfd_device_info carrizo_device_info = { .supports_cwsr = true, .needs_iommu_device = true, .needs_pci_atomics = false, + .num_sdma_engines = 2, +}; + +static const struct kfd_device_info raven_device_info = { + .asic_family = CHIP_RAVEN, + .max_pasid_bits = 16, + .max_no_of_hqd = 24, + .doorbell_size = 8, + .ih_ring_entry_size = 8 * sizeof(uint32_t), + .event_interrupt_class = &event_interrupt_class_v9, + .num_of_watch_points = 4, + .mqd_size_aligned = MQD_SIZE_ALIGNED, + .supports_cwsr = true, + .needs_iommu_device = true, + .needs_pci_atomics = true, + .num_sdma_engines = 1, }; #endif @@ -77,6 +100,7 @@ static const struct kfd_device_info hawaii_device_info = { .supports_cwsr = false, .needs_iommu_device = false, .needs_pci_atomics = false, + .num_sdma_engines = 2, }; static const struct kfd_device_info tonga_device_info = { @@ -91,6 +115,7 @@ static const struct kfd_device_info tonga_device_info = { .supports_cwsr = false, .needs_iommu_device = false, .needs_pci_atomics = true, + .num_sdma_engines = 2, }; static const struct kfd_device_info tonga_vf_device_info = { @@ -105,6 +130,7 @@ static const struct kfd_device_info tonga_vf_device_info = { .supports_cwsr = false, .needs_iommu_device = false, .needs_pci_atomics = false, + .num_sdma_engines = 2, }; static const struct kfd_device_info fiji_device_info = { @@ -119,6 +145,7 @@ static const struct kfd_device_info fiji_device_info = { .supports_cwsr = true, .needs_iommu_device = false, .needs_pci_atomics = true, + .num_sdma_engines = 2, }; static const struct kfd_device_info fiji_vf_device_info = { @@ -133,6 +160,7 @@ static const struct kfd_device_info fiji_vf_device_info = { .supports_cwsr = true, .needs_iommu_device = false, .needs_pci_atomics = false, + .num_sdma_engines = 2, }; @@ -148,6 +176,7 @@ static const struct kfd_device_info polaris10_device_info = { .supports_cwsr = true, .needs_iommu_device = false, .needs_pci_atomics = true, + .num_sdma_engines = 2, }; static const struct kfd_device_info polaris10_vf_device_info = { @@ -162,6 +191,7 @@ static const struct kfd_device_info polaris10_vf_device_info = { .supports_cwsr = true, .needs_iommu_device = false, .needs_pci_atomics = false, + .num_sdma_engines = 2, }; static const struct kfd_device_info polaris11_device_info = { @@ -176,6 +206,7 @@ static const struct kfd_device_info polaris11_device_info = { .supports_cwsr = true, .needs_iommu_device = false, .needs_pci_atomics = true, + .num_sdma_engines = 2, }; static const struct kfd_device_info vega10_device_info = { @@ -190,6 +221,7 @@ static const struct kfd_device_info vega10_device_info = { .supports_cwsr = true, .needs_iommu_device = false, .needs_pci_atomics = false, + .num_sdma_engines = 2, }; static const struct kfd_device_info vega10_vf_device_info = { @@ -204,6 +236,7 @@ static const struct kfd_device_info vega10_vf_device_info = { .supports_cwsr = true, .needs_iommu_device = false, .needs_pci_atomics = false, + .num_sdma_engines = 2, }; @@ -241,6 +274,7 @@ static const struct kfd_deviceid supported_devices[] = { { 0x9875, &carrizo_device_info }, /* Carrizo */ { 0x9876, &carrizo_device_info }, /* Carrizo */ { 0x9877, &carrizo_device_info }, /* Carrizo */ + { 0x15DD, &raven_device_info }, /* Raven */ #endif { 0x67A0, &hawaii_device_info }, /* Hawaii */ { 0x67A1, &hawaii_device_info }, /* Hawaii */ @@ -514,13 +548,54 @@ void kgd2kfd_device_exit(struct kfd_dev *kfd) kfree(kfd); } +int kgd2kfd_pre_reset(struct kfd_dev *kfd) +{ + if (!kfd->init_complete) + return 0; + kgd2kfd_suspend(kfd); + + /* hold dqm->lock to prevent further execution*/ + dqm_lock(kfd->dqm); + + kfd_signal_reset_event(kfd); + return 0; +} + +/* + * Fix me. KFD won't be able to resume existing process for now. + * We will keep all existing process in a evicted state and + * wait the process to be terminated. + */ + +int kgd2kfd_post_reset(struct kfd_dev *kfd) +{ + int ret, count; + + if (!kfd->init_complete) + return 0; + + dqm_unlock(kfd->dqm); + + ret = kfd_resume(kfd); + if (ret) + return ret; + count = atomic_dec_return(&kfd_locked); + WARN_ONCE(count != 0, "KFD reset ref. error"); + return 0; +} + +bool kfd_is_locked(void) +{ + return (atomic_read(&kfd_locked) > 0); +} + void kgd2kfd_suspend(struct kfd_dev *kfd) { if (!kfd->init_complete) return; /* For first KFD device suspend all the KFD processes */ - if (atomic_inc_return(&kfd_device_suspended) == 1) + if (atomic_inc_return(&kfd_locked) == 1) kfd_suspend_all_processes(); kfd->dqm->ops.stop(kfd->dqm); @@ -539,7 +614,7 @@ int kgd2kfd_resume(struct kfd_dev *kfd) if (ret) return ret; - count = atomic_dec_return(&kfd_device_suspended); + count = atomic_dec_return(&kfd_locked); WARN_ONCE(count < 0, "KFD suspend / resume ref. error"); if (count == 0) ret = kfd_resume_all_processes(); @@ -577,14 +652,24 @@ dqm_start_error: /* This is called directly from KGD at ISR. */ void kgd2kfd_interrupt(struct kfd_dev *kfd, const void *ih_ring_entry) { + uint32_t patched_ihre[KFD_MAX_RING_ENTRY_SIZE]; + bool is_patched = false; + if (!kfd->init_complete) return; + if (kfd->device_info->ih_ring_entry_size > sizeof(patched_ihre)) { + dev_err_once(kfd_device, "Ring entry too small\n"); + 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)) + && interrupt_is_wanted(kfd, ih_ring_entry, + patched_ihre, &is_patched) + && enqueue_ih_ring_entry(kfd, + is_patched ? patched_ihre : ih_ring_entry)) queue_work(kfd->ih_wq, &kfd->interrupt_work); spin_unlock(&kfd->interrupt_lock); @@ -739,8 +824,8 @@ int kfd_gtt_sa_allocate(struct kfd_dev *kfd, unsigned int size, if (size > kfd->gtt_sa_num_of_chunks * kfd->gtt_sa_chunk_size) return -ENOMEM; - *mem_obj = kzalloc(sizeof(struct kfd_mem_obj), GFP_NOIO); - if ((*mem_obj) == NULL) + *mem_obj = kzalloc(sizeof(struct kfd_mem_obj), GFP_KERNEL); + if (!(*mem_obj)) return -ENOMEM; pr_debug("Allocated mem_obj = %p for size = %d\n", *mem_obj, size); @@ -857,3 +942,26 @@ int kfd_gtt_sa_free(struct kfd_dev *kfd, struct kfd_mem_obj *mem_obj) kfree(mem_obj); return 0; } + +#if defined(CONFIG_DEBUG_FS) + +/* This function will send a package to HIQ to hang the HWS + * which will trigger a GPU reset and bring the HWS back to normal state + */ +int kfd_debugfs_hang_hws(struct kfd_dev *dev) +{ + int r = 0; + + if (dev->dqm->sched_policy != KFD_SCHED_POLICY_HWS) { + pr_err("HWS is not enabled"); + return -EINVAL; + } + + r = pm_debugfs_hang_hws(&dev->dqm->packets); + if (!r) + r = dqm_debugfs_execute_queues(dev->dqm); + + return r; +} + +#endif |