diff options
Diffstat (limited to 'drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c')
| -rw-r--r-- | drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c | 223 |
1 files changed, 91 insertions, 132 deletions
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c index 67137679a901..5446d89a84b3 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c @@ -37,7 +37,8 @@ #include "amdgpu_amdkfd.h" #include "amdgpu_reset.h" #include "amdgpu_sdma.h" -#include "mes_v11_api_def.h" +#include "amdgpu_ring.h" +#include "amdgpu_mes.h" #include "kfd_debug.h" /* Size of the per-pipe EOP queue */ @@ -71,12 +72,11 @@ static int allocate_sdma_queue(struct device_queue_manager *dqm, struct queue *q, const uint32_t *restore_sdma_id); static int reset_queues_on_hws_hang(struct device_queue_manager *dqm, bool is_sdma); -static int resume_all_queues_mes(struct device_queue_manager *dqm); -static int suspend_all_queues_mes(struct device_queue_manager *dqm); static struct queue *find_queue_by_doorbell_offset(struct device_queue_manager *dqm, u32 doorbell_offset); static void set_queue_as_reset(struct device_queue_manager *dqm, struct queue *q, struct qcm_process_device *qpd); +static int reset_queues_mes(struct device_queue_manager *dqm, struct queue *q); static inline enum KFD_MQD_TYPE get_mqd_type_from_queue_type(enum kfd_queue_type type) @@ -184,24 +184,24 @@ static void kfd_hws_hang(struct device_queue_manager *dqm) amdgpu_amdkfd_gpu_reset(dqm->dev->adev); } -static int convert_to_mes_queue_type(int queue_type) +static int convert_to_amdgpu_ring_type(int queue_type) { - int mes_queue_type; + int amdgpu_ring_type; switch (queue_type) { case KFD_QUEUE_TYPE_COMPUTE: - mes_queue_type = MES_QUEUE_TYPE_COMPUTE; + amdgpu_ring_type = AMDGPU_RING_TYPE_COMPUTE; break; case KFD_QUEUE_TYPE_SDMA: - mes_queue_type = MES_QUEUE_TYPE_SDMA; + amdgpu_ring_type = AMDGPU_RING_TYPE_SDMA; break; default: WARN(1, "Invalid queue type %d", queue_type); - mes_queue_type = -EINVAL; + amdgpu_ring_type = -EINVAL; break; } - return mes_queue_type; + return amdgpu_ring_type; } static int add_queue_mes(struct device_queue_manager *dqm, struct queue *q, @@ -251,7 +251,7 @@ static int add_queue_mes(struct device_queue_manager *dqm, struct queue *q, (qpd->pqm->process->debug_trap_enabled || kfd_dbg_has_ttmps_always_setup(q->device)); - queue_type = convert_to_mes_queue_type(q->properties.type); + queue_type = convert_to_amdgpu_ring_type(q->properties.type); if (queue_type < 0) { dev_err(adev->dev, "Queue type not supported with MES, queue:%d\n", q->properties.type); @@ -300,6 +300,7 @@ static int remove_queue_mes_on_reset_option(struct device_queue_manager *dqm, st memset(&queue_input, 0x0, sizeof(struct mes_remove_queue_input)); queue_input.doorbell_offset = q->properties.doorbell_off; queue_input.gang_context_addr = q->gang_ctx_gpu_addr; + queue_input.queue_type = convert_to_amdgpu_ring_type(q->properties.type); queue_input.remove_queue_after_reset = flush_mes_queue; queue_input.xcc_id = ffs(dqm->dev->xcc_mask) - 1; @@ -308,14 +309,14 @@ static int remove_queue_mes_on_reset_option(struct device_queue_manager *dqm, st amdgpu_mes_unlock(&adev->mes); up_read(&adev->reset_domain->sem); - if (is_for_reset) + /* If is_for_reset set, it is a mes internal cleanup */ + if (!r || is_for_reset) return r; - if (r) { - if (!suspend_all_queues_mes(dqm)) - return resume_all_queues_mes(dqm); - - dev_err(adev->dev, "failed to remove hardware queue from MES, doorbell=0x%x\n", + /* remove_hw_queue failure indicates a queue hang. reset the queue */ + r = reset_queues_mes(dqm, q); + if (r && amdgpu_gpu_recovery) { + dev_err(adev->dev, "failed to remove queue from MES, doorbell=0x%x\n", q->properties.doorbell_off); dev_err(adev->dev, "MES might be in unrecoverable state, issue a GPU reset\n"); kfd_hws_hang(dqm); @@ -407,16 +408,50 @@ static int add_all_kfd_queues_mes(struct device_queue_manager *dqm) return retval; } -static int reset_queues_mes(struct device_queue_manager *dqm) +static int reset_queue_mes(struct device_queue_manager *dqm, struct queue *q, + int queue_type, int pipe, int queue, unsigned int db) { struct amdgpu_device *adev = (struct amdgpu_device *)dqm->dev->adev; - int hqd_info_size = adev->mes.hung_queue_hqd_info_offset; - int num_hung = 0, r = 0, i, pipe, queue, queue_type; - u32 *hung_array = dqm->hung_db_array; - struct amdgpu_mes_hung_queue_hqd_info *hqd_info = dqm->hqd_info; struct kfd_process_device *pdd; + bool use_mmio = adev->gfx.mec.use_mmio_for_reset; + int r; + + pdd = kfd_get_process_device_data(q->device, q->process); + if (!pdd) + return -ENODEV; + + if (use_mmio) + r = amdgpu_mes_reset_queue_mmio(adev, queue_type, 0, 1, pipe, queue, + ffs(dqm->dev->xcc_mask) - 1); + else + r = amdgpu_mes_reset_user_queue(adev, queue_type, db, + ffs(dqm->dev->xcc_mask) - 1); + if (r) + return r; + /* Proceed remove_queue with reset=true */ + remove_queue_mes_on_reset_option(dqm, q, &pdd->qpd, true, true); + set_queue_as_reset(dqm, q, &pdd->qpd); + return 0; +} + +int kfd_reset_queue_mes(struct device_queue_manager *dqm, int queue_type, + int pipe, int queue, unsigned int db) +{ struct queue *q; + q = find_queue_by_doorbell_offset(dqm, db); + if (!q) + return 0; + return reset_queue_mes(dqm, q, queue_type, pipe, queue, db); +} + +static int reset_queues_mes(struct device_queue_manager *dqm, struct queue *q) +{ + struct amdgpu_device *adev = (struct amdgpu_device *)dqm->dev->adev; + unsigned int num_hung = 0; + int r = 0; + struct mes_remove_queue_input queue_input; + if (!amdgpu_mes_queue_reset_by_mes_supported(adev)) { r = -ENOTRECOVERABLE; goto fail; @@ -431,111 +466,29 @@ static int reset_queues_mes(struct device_queue_manager *dqm) goto fail; } - if (!hung_array || !hqd_info) { - r = -ENOMEM; - goto fail; - } - - memset(hqd_info, 0, hqd_info_size * sizeof(struct amdgpu_mes_hung_queue_hqd_info)); - - /* - * AMDGPU_RING_TYPE_COMPUTE parameter does not matter if called - * post suspend_all as reset & detect will return all hung queue types. - * - * Passed parameter is for targeting queues not scheduled by MES add_queue. - */ - r = amdgpu_mes_detect_and_reset_hung_queues(adev, AMDGPU_RING_TYPE_COMPUTE, - false, &num_hung, hung_array, ffs(dqm->dev->xcc_mask) - 1); - - if (!num_hung || r) { - r = -ENOTRECOVERABLE; + memset(&queue_input, 0x0, sizeof(struct mes_remove_queue_input)); + queue_input.doorbell_offset = q->properties.doorbell_off; + queue_input.gang_context_addr = q->gang_ctx_gpu_addr; + queue_input.queue_type = convert_to_amdgpu_ring_type(q->properties.type); + queue_input.remove_queue_after_reset = false; + queue_input.xcc_id = ffs(dqm->dev->xcc_mask) - 1; + /* pass the known bad queue info to the reset function */ + r = amdgpu_gfx_reset_mes_compute(adev, NULL, NULL, NULL, &num_hung, &queue_input); + if (r) goto fail; - } - - /* MES resets queue/pipe and cleans up internally */ - for (i = 0; i < num_hung; i++) { - hqd_info[i].bit0_31 = hung_array[i + hqd_info_size]; - pipe = hqd_info[i].pipe_index; - queue = hqd_info[i].queue_index; - queue_type = hqd_info[i].queue_type; - - if (queue_type != MES_QUEUE_TYPE_COMPUTE && - queue_type != MES_QUEUE_TYPE_SDMA) { - pr_warn("Unsupported hung queue reset type: %d\n", queue_type); - hung_array[i] = AMDGPU_MES_INVALID_DB_OFFSET; - continue; - } - - q = find_queue_by_doorbell_offset(dqm, hung_array[i]); - if (!q) { - r = -ENOTRECOVERABLE; - goto fail; - } - - pdd = kfd_get_process_device_data(q->device, q->process); - if (!pdd) { - r = -ENODEV; - goto fail; - } - - pr_warn("Hang detected doorbell %x pipe %d queue %d type %d\n", - hung_array[i], pipe, queue, queue_type); - /* Proceed remove_queue with reset=true */ - remove_queue_mes_on_reset_option(dqm, q, &pdd->qpd, true, false); - set_queue_as_reset(dqm, q, &pdd->qpd); - } dqm->detect_hang_count = num_hung; - kfd_signal_reset_event(dqm->dev); + /* When MES doesn't detect any queue hang, no reset happens. Don't signal reset + * event. + */ + if (dqm->detect_hang_count) + kfd_signal_reset_event(dqm->dev); fail: dqm->detect_hang_count = 0; return r; } -static int suspend_all_queues_mes(struct device_queue_manager *dqm) -{ - struct amdgpu_device *adev = (struct amdgpu_device *)dqm->dev->adev; - int r = 0; - - if (!down_read_trylock(&adev->reset_domain->sem)) - return -EIO; - - r = amdgpu_mes_suspend(adev, ffs(dqm->dev->xcc_mask) - 1); - up_read(&adev->reset_domain->sem); - - if (r) { - if (!reset_queues_mes(dqm)) - return 0; - - dev_err(adev->dev, "failed to suspend gangs from MES\n"); - dev_err(adev->dev, "MES might be in unrecoverable state, issue a GPU reset\n"); - kfd_hws_hang(dqm); - } - - return r; -} - -static int resume_all_queues_mes(struct device_queue_manager *dqm) -{ - struct amdgpu_device *adev = (struct amdgpu_device *)dqm->dev->adev; - int r = 0; - - if (!down_read_trylock(&adev->reset_domain->sem)) - return -EIO; - - r = amdgpu_mes_resume(adev, ffs(dqm->dev->xcc_mask) - 1); - up_read(&adev->reset_domain->sem); - - if (r) { - dev_err(adev->dev, "failed to resume gangs from MES\n"); - dev_err(adev->dev, "MES might be in unrecoverable state, issue a GPU reset\n"); - kfd_hws_hang(dqm); - } - - return r; -} - static void increment_queue_count(struct device_queue_manager *dqm, struct qcm_process_device *qpd, struct queue *q) @@ -1064,8 +1017,15 @@ static int destroy_queue_nocpsch(struct device_queue_manager *dqm, /* Get the SDMA queue stats */ if ((q->properties.type == KFD_QUEUE_TYPE_SDMA) || (q->properties.type == KFD_QUEUE_TYPE_SDMA_XGMI)) { - retval = read_sdma_queue_counter((uint64_t __user *)q->properties.read_ptr, - &sdma_val); + if (dqm->dev->kfd2kgd->hqd_sdma_get_counter) + retval = dqm->dev->kfd2kgd->hqd_sdma_get_counter( + dqm->dev->adev, q->mqd, + dqm->dev->kfd->device_info.num_sdma_queues_per_engine, + &sdma_val); + else + retval = read_sdma_queue_counter( + (uint64_t __user *)q->properties.read_ptr, + &sdma_val); if (retval) dev_err(dev, "Failed to read SDMA queue counter for queue: %d\n", q->properties.queue_id); @@ -2703,8 +2663,16 @@ static int destroy_queue_cpsch(struct device_queue_manager *dqm, /* Get the SDMA queue stats */ if ((q->properties.type == KFD_QUEUE_TYPE_SDMA) || (q->properties.type == KFD_QUEUE_TYPE_SDMA_XGMI)) { - retval = read_sdma_queue_counter((uint64_t __user *)q->properties.read_ptr, - &sdma_val); + if (dqm->dev->kfd2kgd->hqd_sdma_get_counter) + retval = dqm->dev->kfd2kgd->hqd_sdma_get_counter( + dqm->dev->adev, q->mqd, + dqm->dev->kfd->device_info.num_sdma_queues_per_engine, + &sdma_val); + else + retval = read_sdma_queue_counter( + (uint64_t __user *)q->properties.read_ptr, + &sdma_val); + if (retval) dev_err(dev, "Failed to read SDMA queue counter for queue: %d\n", q->properties.queue_id); @@ -3248,12 +3216,12 @@ void device_queue_manager_uninit(struct device_queue_manager *dqm) kfree(dqm); } +/* bad queue notified by interrupt from CP */ int kfd_dqm_suspend_bad_queue_mes(struct kfd_node *knode, u32 pasid, u32 doorbell_id) { struct kfd_process_device *pdd = NULL; struct kfd_process *p = kfd_lookup_process_by_pasid(pasid, &pdd); struct device_queue_manager *dqm = knode->dqm; - struct device *dev = dqm->dev->adev->dev; struct qcm_process_device *qpd; struct queue *q = NULL; int ret = 0; @@ -3268,19 +3236,10 @@ int kfd_dqm_suspend_bad_queue_mes(struct kfd_node *knode, u32 pasid, u32 doorbel list_for_each_entry(q, &qpd->queues_list, list) { if (q->doorbell_id == doorbell_id && q->properties.is_active) { - /* suspend all queues will save any good queues and mark the rest as bad */ - suspend_all_queues_mes(dqm); - + reset_queues_mes(dqm, q); q->properties.is_evicted = true; q->properties.is_active = false; decrement_queue_count(dqm, qpd, q); - - /* this will remove the bad queue and sched a GPU reset if needed */ - ret = remove_queue_mes(dqm, q, qpd); - if (ret) - dev_err(dev, "Removing bad queue failed"); - /* resume the good queues */ - resume_all_queues_mes(dqm); break; } } |
