diff options
Diffstat (limited to 'drivers/gpu/drm/amd/amdkfd/kfd_process.c')
| -rw-r--r-- | drivers/gpu/drm/amd/amdkfd/kfd_process.c | 147 |
1 files changed, 118 insertions, 29 deletions
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c index 5fb3679e4e85..eb508fe3ded7 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c @@ -33,6 +33,7 @@ #include <linux/mman.h> #include <linux/file.h> #include <linux/pm_runtime.h> +#include <drm/ttm/ttm_bo.h> #include "amdgpu_amdkfd.h" #include "amdgpu.h" #include "amdgpu_reset.h" @@ -153,6 +154,21 @@ static void kfd_sdma_activity_worker(struct work_struct *work) (q->properties.type != KFD_QUEUE_TYPE_SDMA_XGMI)) continue; + if (dqm->dev->kfd2kgd->hqd_sdma_get_counter) { + val = 0; + ret = dqm->dev->kfd2kgd->hqd_sdma_get_counter( + dqm->dev->adev, q->mqd, + dqm->dev->kfd->device_info.num_sdma_queues_per_engine, + &val); + + if (ret) + pr_debug("Failed to read SDMA queue active counter %i\n", ret); + else + workarea->sdma_activity_counter += val; + + continue; + } + sdma_q = kzalloc_obj(struct temp_sdma_queue_list); if (!sdma_q) { dqm_unlock(dqm); @@ -171,7 +187,7 @@ static void kfd_sdma_activity_worker(struct work_struct *work) * count */ if (list_empty(&sdma_q_list.list)) { - workarea->sdma_activity_counter = pdd->sdma_past_activity_counter; + workarea->sdma_activity_counter += pdd->sdma_past_activity_counter; dqm_unlock(dqm); return; } @@ -721,7 +737,7 @@ static void kfd_process_free_gpuvm(struct kgd_mem *mem, struct kfd_node *dev = pdd->dev; if (kptr && *kptr) { - amdgpu_amdkfd_gpuvm_unmap_gtt_bo_from_kernel(mem); + amdgpu_amdkfd_gpuvm_unmap_bo_from_kernel(mem); *kptr = NULL; } @@ -730,6 +746,22 @@ static void kfd_process_free_gpuvm(struct kgd_mem *mem, NULL); } +static void kfd_process_free_gpuvm_map(struct kgd_mem *mem, + struct kfd_process_device *pdd, + struct iosys_map *map) +{ + struct kfd_node *dev = pdd->dev; + + if (map && !iosys_map_is_null(map)) { + amdgpu_amdkfd_gpuvm_unmap_bo_from_kernel(mem); + iosys_map_clear(map); + } + + amdgpu_amdkfd_gpuvm_unmap_memory_from_gpu(dev->adev, mem, pdd->drm_priv); + amdgpu_amdkfd_gpuvm_free_memory_of_gpu(dev->adev, mem, pdd->drm_priv, + NULL); +} + /* kfd_process_alloc_gpuvm - Allocate GPU VM for the KFD process * This function should be only called right after the process * is created and when kfd_processes_mutex is still being held @@ -761,10 +793,16 @@ static int kfd_process_alloc_gpuvm(struct kfd_process_device *pdd, } if (kptr) { - err = amdgpu_amdkfd_gpuvm_map_gtt_bo_to_kernel( - (struct kgd_mem *)*mem, kptr, NULL); + u32 domain; + + if (flags & KFD_IOC_ALLOC_MEM_FLAGS_VRAM) + domain = AMDGPU_GEM_DOMAIN_VRAM; + else + domain = AMDGPU_GEM_DOMAIN_GTT; + err = amdgpu_amdkfd_gpuvm_map_bo_to_kernel((struct kgd_mem *)*mem, + kptr, NULL, domain); if (err) { - pr_debug("Map GTT BO to kernel failed\n"); + pr_debug("Map BO to kernel failed err %d\n", err); goto sync_memory_failed; } } @@ -975,7 +1013,10 @@ struct kfd_process *kfd_create_process(struct task_struct *thread) if (ret) pr_warn("Failed to create sysfs entry for the kfd_process"); - kfd_debugfs_add_process(process); + ret = kfd_debugfs_add_process(process); + if (ret) + pr_warn("Failed to create debugfs entry for the kfd_process, ret = %d\n", + ret); init_waitqueue_head(&process->wait_irq_drain); } @@ -986,6 +1027,33 @@ out: return process; } +/** + * amdgpu_amdkfd_set_sigbus_delay - Set per-process KFD SIGBUS delay + * @task: task in the target process + * @ms: encoded delay value (0 = immediate, 0xFFFFFFFF = suppress, + * otherwise delay in milliseconds) + * + * Stores the SIGBUS delivery option on the kfd_process associated with + * @task. If the calling process has not opened /dev/kfd yet (no + * kfd_process exists), this is a no-op - the option only applies to + * processes that actually use KFD. + */ +int amdgpu_amdkfd_set_sigbus_delay(struct task_struct *task, u32 ms) +{ + struct kfd_process *p; + + if (!task->mm) + return -EINVAL; + + p = kfd_lookup_process_by_mm(task->mm); + if (!p) + return 0; + + atomic_set(&p->kfd_sigbus_delay_ms, ms); + kfd_unref_process(p); + return 0; +} + static struct kfd_process *find_process_by_mm(const struct mm_struct *mm) { struct kfd_process *process; @@ -1092,7 +1160,7 @@ static void kfd_process_kunmap_signal_bo(struct kfd_process *p) if (!mem) goto out; - amdgpu_amdkfd_gpuvm_unmap_gtt_bo_from_kernel(mem); + amdgpu_amdkfd_gpuvm_unmap_bo_from_kernel(mem); out: mutex_unlock(&p->mutex); @@ -1138,9 +1206,9 @@ static void kfd_process_destroy_pdds(struct kfd_process *p) if (pdd->drm_file) fput(pdd->drm_file); - if (pdd->qpd.cwsr_kaddr && !pdd->qpd.cwsr_base) - free_pages((unsigned long)pdd->qpd.cwsr_kaddr, - get_order(KFD_CWSR_TBA_TMA_SIZE)); + if (!iosys_map_is_null(&pdd->qpd.cwsr_map) && !pdd->qpd.cwsr_base) + free_pages((unsigned long)pdd->qpd.cwsr_map.vaddr, + get_order(KFD_CWSR_TBA_TMA_SIZE)); idr_destroy(&pdd->alloc_idr); @@ -1330,6 +1398,11 @@ void kfd_process_notifier_release_internal(struct kfd_process *p) kfd_process_table_remove(p); cancel_delayed_work_sync(&p->eviction_work); cancel_delayed_work_sync(&p->restore_work); + /* + * If work pending, cancel it and drop the extra ref + */ + if (cancel_delayed_work_sync(&p->signal_work)) + kfd_unref_process(p); /* * Dequeue and destroy user queues, it is not safe for GPU to access @@ -1436,34 +1509,49 @@ static int kfd_process_device_init_cwsr_dgpu(struct kfd_process_device *pdd) { struct kfd_node *dev = pdd->dev; struct qcm_process_device *qpd = &pdd->qpd; - uint32_t flags = KFD_IOC_ALLOC_MEM_FLAGS_GTT - | KFD_IOC_ALLOC_MEM_FLAGS_NO_SUBSTITUTE + u32 flags = KFD_IOC_ALLOC_MEM_FLAGS_NO_SUBSTITUTE | KFD_IOC_ALLOC_MEM_FLAGS_EXECUTABLE; struct kgd_mem *mem; void *kaddr; int ret; - if (!dev->kfd->cwsr_enabled || qpd->cwsr_kaddr || !qpd->cwsr_base) + if (!dev->kfd->cwsr_enabled || !iosys_map_is_null(&qpd->cwsr_map) || !qpd->cwsr_base) return 0; - /* cwsr_base is only set for dGPU */ + if (KFD_GC_VERSION(dev) >= IP_VERSION(9, 4, 2) && !dev->adev->apu_prefer_gtt) + flags |= KFD_IOC_ALLOC_MEM_FLAGS_VRAM; + else + flags |= KFD_IOC_ALLOC_MEM_FLAGS_GTT; + + /* Allocate CWSR TBA/TMA buffers */ ret = kfd_process_alloc_gpuvm(pdd, qpd->cwsr_base, KFD_CWSR_TBA_TMA_SIZE, flags, &mem, &kaddr); if (ret) return ret; qpd->cwsr_mem = mem; - qpd->cwsr_kaddr = kaddr; + + /* Set up iosys_map based on whether memory is MMIO or system memory */ + if (mem->bo->kmap.bo_kmap_type & TTM_BO_MAP_IOMEM_MASK) + iosys_map_set_vaddr_iomem(&qpd->cwsr_map, kaddr); + else + iosys_map_set_vaddr(&qpd->cwsr_map, kaddr); + qpd->tba_addr = qpd->cwsr_base; - memcpy(qpd->cwsr_kaddr, dev->kfd->cwsr_isa, dev->kfd->cwsr_isa_size); + /* Copy CWSR ISA to buffer using appropriate accessor */ + iosys_map_memcpy_to(&qpd->cwsr_map, 0, dev->kfd->cwsr_isa, + dev->kfd->cwsr_isa_size); kfd_process_set_trap_debug_flag(&pdd->qpd, pdd->process->debug_trap_enabled); qpd->tma_addr = qpd->tba_addr + KFD_CWSR_TMA_OFFSET; - pr_debug("set tba :0x%llx, tma:0x%llx, cwsr_kaddr:%p for pqm.\n", - qpd->tba_addr, qpd->tma_addr, qpd->cwsr_kaddr); + pr_debug("set tba :0x%llx, tma:0x%llx, cwsr_map:%s at %p for pqm.\n", + qpd->tba_addr, qpd->tma_addr, + qpd->cwsr_map.is_iomem ? "iomem" : "system", + qpd->cwsr_map.is_iomem ? (void *)qpd->cwsr_map.vaddr_iomem : + qpd->cwsr_map.vaddr); return 0; } @@ -1473,24 +1561,24 @@ static void kfd_process_device_destroy_cwsr_dgpu(struct kfd_process_device *pdd) struct kfd_node *dev = pdd->dev; struct qcm_process_device *qpd = &pdd->qpd; - if (!dev->kfd->cwsr_enabled || !qpd->cwsr_kaddr || !qpd->cwsr_base) + if (!dev->kfd->cwsr_enabled || iosys_map_is_null(&qpd->cwsr_map) || !qpd->cwsr_base) return; - kfd_process_free_gpuvm(qpd->cwsr_mem, pdd, &qpd->cwsr_kaddr); + kfd_process_free_gpuvm_map(qpd->cwsr_mem, pdd, &qpd->cwsr_map); } void kfd_process_set_trap_handler(struct qcm_process_device *qpd, uint64_t tba_addr, uint64_t tma_addr) { - if (qpd->cwsr_kaddr) { + if (!iosys_map_is_null(&qpd->cwsr_map)) { /* KFD trap handler is bound, record as second-level TBA/TMA * in first-level TMA. First-level trap will jump to second. */ - uint64_t *tma = - (uint64_t *)(qpd->cwsr_kaddr + KFD_CWSR_TMA_OFFSET); - tma[0] = tba_addr; - tma[1] = tma_addr; + iosys_map_wr(&qpd->cwsr_map, KFD_CWSR_TMA_OFFSET, + uint64_t, tba_addr); + iosys_map_wr(&qpd->cwsr_map, KFD_CWSR_TMA_OFFSET + sizeof(uint64_t), + uint64_t, tma_addr); } else { /* No trap handler bound, bind as first-level TBA/TMA. */ qpd->tba_addr = tba_addr; @@ -1556,10 +1644,10 @@ bool kfd_process_xnack_mode(struct kfd_process *p, bool supported) void kfd_process_set_trap_debug_flag(struct qcm_process_device *qpd, bool enabled) { - if (qpd->cwsr_kaddr) { - uint64_t *tma = - (uint64_t *)(qpd->cwsr_kaddr + KFD_CWSR_TMA_OFFSET); - tma[2] = enabled; + if (!iosys_map_is_null(&qpd->cwsr_map)) { + iosys_map_wr(&qpd->cwsr_map, + KFD_CWSR_TMA_OFFSET + 2 * sizeof(uint64_t), + uint64_t, enabled); } } @@ -1586,6 +1674,7 @@ struct kfd_process *create_process(const struct task_struct *thread, bool primar INIT_DELAYED_WORK(&process->eviction_work, evict_process_worker); INIT_DELAYED_WORK(&process->restore_work, restore_process_worker); + INIT_DELAYED_WORK(&process->signal_work, kfd_signal_sigbus_delayed_fn); process->last_restore_timestamp = get_jiffies_64(); err = kfd_event_init_process(process); if (err) |
