4058 lines · 107.5 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0 OR MIT/* * Copyright 2014-2022 Advanced Micro Devices, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * */ #include <linux/ratelimit.h>#include <linux/printk.h>#include <linux/slab.h>#include <linux/list.h>#include <linux/types.h>#include <linux/bitops.h>#include <linux/sched.h>#include "kfd_priv.h"#include "kfd_device_queue_manager.h"#include "kfd_mqd_manager.h"#include "cik_regs.h"#include "kfd_kernel_queue.h"#include "amdgpu_amdkfd.h"#include "amdgpu_reset.h"#include "amdgpu_sdma.h"#include "amdgpu_ring.h"#include "amdgpu_mes.h"#include "kfd_debug.h" /* Size of the per-pipe EOP queue */#define CIK_HPD_EOP_BYTES_LOG2 11#define CIK_HPD_EOP_BYTES (1U << CIK_HPD_EOP_BYTES_LOG2)/* See unmap_queues_cpsch() */#define USE_DEFAULT_GRACE_PERIOD 0xffffffff static int set_pasid_vmid_mapping(struct device_queue_manager *dqm,				  u32 pasid, unsigned int vmid); static int execute_queues_cpsch(struct device_queue_manager *dqm,				enum kfd_unmap_queues_filter filter,				uint32_t filter_param,				uint32_t grace_period);static int unmap_queues_cpsch(struct device_queue_manager *dqm,				enum kfd_unmap_queues_filter filter,				uint32_t filter_param,				uint32_t grace_period,				bool reset); static int map_queues_cpsch(struct device_queue_manager *dqm); static void deallocate_sdma_queue(struct device_queue_manager *dqm,				struct queue *q); static inline void deallocate_hqd(struct device_queue_manager *dqm,				struct queue *q);static int allocate_hqd(struct device_queue_manager *dqm, struct queue *q);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 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 inlineenum KFD_MQD_TYPE get_mqd_type_from_queue_type(enum kfd_queue_type type){	if (type == KFD_QUEUE_TYPE_SDMA || type == KFD_QUEUE_TYPE_SDMA_XGMI)		return KFD_MQD_TYPE_SDMA;	return KFD_MQD_TYPE_CP;} static bool is_pipe_enabled(struct device_queue_manager *dqm, int mec, int pipe){	int i;	int pipe_offset = (mec * dqm->dev->kfd->shared_resources.num_pipe_per_mec		+ pipe) * dqm->dev->kfd->shared_resources.num_queue_per_pipe; 	/* queue is available for KFD usage if bit is 1 */	for (i = 0; i <  dqm->dev->kfd->shared_resources.num_queue_per_pipe; ++i)		if (test_bit(pipe_offset + i,			      dqm->dev->kfd->shared_resources.cp_queue_bitmap))			return true;	return false;} unsigned int get_cp_queues_num(struct device_queue_manager *dqm){	return bitmap_weight(dqm->dev->kfd->shared_resources.cp_queue_bitmap,				AMDGPU_MAX_QUEUES);} unsigned int get_queues_per_pipe(struct device_queue_manager *dqm){	return dqm->dev->kfd->shared_resources.num_queue_per_pipe;} unsigned int get_pipes_per_mec(struct device_queue_manager *dqm){	return dqm->dev->kfd->shared_resources.num_pipe_per_mec;} static unsigned int get_num_all_sdma_engines(struct device_queue_manager *dqm){	return kfd_get_num_sdma_engines(dqm->dev) +		kfd_get_num_xgmi_sdma_engines(dqm->dev);} unsigned int get_num_sdma_queues(struct device_queue_manager *dqm){	return kfd_get_num_sdma_engines(dqm->dev) *		dqm->dev->kfd->device_info.num_sdma_queues_per_engine;} unsigned int get_num_xgmi_sdma_queues(struct device_queue_manager *dqm){	return kfd_get_num_xgmi_sdma_engines(dqm->dev) *		dqm->dev->kfd->device_info.num_sdma_queues_per_engine;} static void init_sdma_bitmaps(struct device_queue_manager *dqm){	bitmap_zero(dqm->sdma_bitmap, KFD_MAX_SDMA_QUEUES);	bitmap_set(dqm->sdma_bitmap, 0, get_num_sdma_queues(dqm)); 	bitmap_zero(dqm->xgmi_sdma_bitmap, KFD_MAX_SDMA_QUEUES);	bitmap_set(dqm->xgmi_sdma_bitmap, 0, get_num_xgmi_sdma_queues(dqm)); 	/* Mask out the reserved queues */	bitmap_clear(dqm->sdma_bitmap, 0, kfd_get_num_sdma_engines(dqm->dev) *			dqm->dev->kfd->device_info.num_reserved_sdma_queues_per_engine);	bitmap_clear(dqm->xgmi_sdma_bitmap, 0, kfd_get_num_xgmi_sdma_engines(dqm->dev) *			dqm->dev->kfd->device_info.num_reserved_sdma_queues_per_engine);} void program_sh_mem_settings(struct device_queue_manager *dqm,					struct qcm_process_device *qpd){	uint32_t xcc_mask = dqm->dev->xcc_mask;	int xcc_id; 	for_each_inst(xcc_id, xcc_mask)		dqm->dev->kfd2kgd->program_sh_mem_settings(			dqm->dev->adev, qpd->vmid, qpd->sh_mem_config,			qpd->sh_mem_ape1_base, qpd->sh_mem_ape1_limit,			qpd->sh_mem_bases, xcc_id);} static void kfd_hws_hang(struct device_queue_manager *dqm){	struct device_process_node *cur;	struct qcm_process_device *qpd;	struct queue *q; 	/* Mark all device queues as reset. */	list_for_each_entry(cur, &dqm->queues, list) {		qpd = cur->qpd;		list_for_each_entry(q, &qpd->queues_list, list) {			struct kfd_process_device *pdd = qpd_to_pdd(qpd); 			pdd->has_reset_queue = true;		}	} 	/*	 * Issue a GPU reset if HWS is unresponsive	 */	amdgpu_amdkfd_gpu_reset(dqm->dev->adev);} static int convert_to_amdgpu_ring_type(int queue_type){	int amdgpu_ring_type; 	switch (queue_type) {	case KFD_QUEUE_TYPE_COMPUTE:		amdgpu_ring_type = AMDGPU_RING_TYPE_COMPUTE;		break;	case KFD_QUEUE_TYPE_SDMA:		amdgpu_ring_type = AMDGPU_RING_TYPE_SDMA;		break;	default:		WARN(1, "Invalid queue type %d", queue_type);		amdgpu_ring_type = -EINVAL;		break;	} 	return amdgpu_ring_type;} static int add_queue_mes(struct device_queue_manager *dqm, struct queue *q,			 struct qcm_process_device *qpd){	struct amdgpu_device *adev = (struct amdgpu_device *)dqm->dev->adev;	struct kfd_process_device *pdd = qpd_to_pdd(qpd);	struct mes_add_queue_input queue_input;	int r, queue_type;	uint64_t wptr_addr_off; 	if (!dqm->sched_running || dqm->sched_halt)		return 0;	if (!down_read_trylock(&adev->reset_domain->sem))		return -EIO; 	memset(&queue_input, 0x0, sizeof(struct mes_add_queue_input));	queue_input.process_id = pdd->pasid;	queue_input.page_table_base_addr =  qpd->page_table_base;	queue_input.process_va_start = 0;	queue_input.process_va_end = adev->vm_manager.max_pfn - 1;	/* MES unit for quantum is 100ns */	queue_input.process_quantum = KFD_MES_PROCESS_QUANTUM;  /* Equivalent to 10ms. */	queue_input.process_context_addr = pdd->proc_ctx_gpu_addr;	queue_input.process_context_array_index = pdd->proc_ctx_array_index;	queue_input.gang_quantum = KFD_MES_GANG_QUANTUM; /* Equivalent to 1ms */	queue_input.gang_context_addr = q->gang_ctx_gpu_addr;	queue_input.gang_context_array_index = q->gang_ctx_array_index;	queue_input.inprocess_gang_priority = q->properties.priority;	queue_input.gang_global_priority_level =					AMDGPU_MES_PRIORITY_LEVEL_NORMAL;	queue_input.doorbell_offset = q->properties.doorbell_off;	queue_input.mqd_addr = q->gart_mqd_addr;	queue_input.wptr_addr = (uint64_t)q->properties.write_ptr; 	wptr_addr_off = (uint64_t)q->properties.write_ptr & (PAGE_SIZE - 1);	queue_input.wptr_mc_addr = amdgpu_bo_gpu_offset(q->properties.wptr_bo) + wptr_addr_off; 	queue_input.is_kfd_process = 1;	queue_input.is_aql_queue = (q->properties.format == KFD_QUEUE_FORMAT_AQL);	queue_input.queue_size = q->properties.queue_size >> 2; 	queue_input.paging = false;	queue_input.tba_addr = qpd->tba_addr;	queue_input.tma_addr = qpd->tma_addr;	queue_input.trap_en = !kfd_dbg_has_cwsr_workaround(q->device);	queue_input.skip_process_ctx_clear =		qpd->pqm->process->runtime_info.runtime_state == DEBUG_RUNTIME_STATE_ENABLED &&						(qpd->pqm->process->debug_trap_enabled ||						 kfd_dbg_has_ttmps_always_setup(q->device)); 	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);		up_read(&adev->reset_domain->sem);		return -EINVAL;	}	queue_input.queue_type = (uint32_t)queue_type; 	queue_input.exclusively_scheduled = q->properties.is_gws;	queue_input.sh_mem_config_data = qpd->sh_mem_config;	queue_input.vm_cntx_cntl = qpd->vm_cntx_cntl;	queue_input.xcc_id = ffs(dqm->dev->xcc_mask) - 1; 	amdgpu_mes_lock(&adev->mes);	r = adev->mes.funcs->add_hw_queue(&adev->mes, &queue_input);	amdgpu_mes_unlock(&adev->mes);	up_read(&adev->reset_domain->sem);	if (r) {		dev_err(adev->dev, "failed to add hardware queue to 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);	} 	return r;} static int remove_queue_mes_on_reset_option(struct device_queue_manager *dqm, struct queue *q,					    struct qcm_process_device *qpd,					    bool is_for_reset,					    bool flush_mes_queue){	struct amdgpu_device *adev = (struct amdgpu_device *)dqm->dev->adev;	int r;	struct mes_remove_queue_input queue_input; 	/* queue was already removed during reset */	if (q->properties.is_reset)		return 0; 	if (!dqm->sched_running || dqm->sched_halt)		return 0;	if (!down_read_trylock(&adev->reset_domain->sem))		return -EIO; 	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;	queue_input.gang_context_array_index = q->gang_ctx_array_index; 	amdgpu_mes_lock(&adev->mes);	r = adev->mes.funcs->remove_hw_queue(&adev->mes, &queue_input);	amdgpu_mes_unlock(&adev->mes);	up_read(&adev->reset_domain->sem); 	/* If is_for_reset set, it is a mes internal cleanup */	if (!r || is_for_reset)		return r; 	/* 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);	} 	return r;} static void set_perfcount(struct device_queue_manager *dqm, int enable){	struct device_process_node *cur;	struct qcm_process_device *qpd;	struct queue *q;	struct mqd_update_info minfo = { 0 }; 	if (!dqm)		return; 	minfo.update_flag = (enable == 1 ? UPDATE_FLAG_PERFCOUNT_ENABLE :						 UPDATE_FLAG_PERFCOUNT_DISABLE);	dqm_lock(dqm);	list_for_each_entry(cur, &dqm->queues, list) {		qpd = cur->qpd;		list_for_each_entry(q, &qpd->queues_list, list) {			pqm_update_mqd(qpd->pqm, q->properties.queue_id,						&minfo);		}	}	dqm_unlock(dqm);} static int remove_queue_mes(struct device_queue_manager *dqm, struct queue *q,			    struct qcm_process_device *qpd){	return remove_queue_mes_on_reset_option(dqm, q, qpd, false, false);} static int remove_all_kfd_queues_mes(struct device_queue_manager *dqm){	struct device_process_node *cur;	struct device *dev = dqm->dev->adev->dev;	struct qcm_process_device *qpd;	struct queue *q;	int retval = 0; 	list_for_each_entry(cur, &dqm->queues, list) {		qpd = cur->qpd;		list_for_each_entry(q, &qpd->queues_list, list) {			if (q->properties.is_active) {				retval = remove_queue_mes(dqm, q, qpd);				if (retval) {					dev_err(dev, "%s: Failed to remove queue %d for dev %d",						__func__,						q->properties.queue_id,						dqm->dev->id);					return retval;				}			}		}	} 	return retval;} static int add_all_kfd_queues_mes(struct device_queue_manager *dqm){	struct device_process_node *cur;	struct device *dev = dqm->dev->adev->dev;	struct qcm_process_device *qpd;	struct queue *q;	int retval = 0; 	list_for_each_entry(cur, &dqm->queues, list) {		qpd = cur->qpd;		list_for_each_entry(q, &qpd->queues_list, list) {			if (!q->properties.is_active)				continue;			retval = add_queue_mes(dqm, q, qpd);			if (retval) {				dev_err(dev, "%s: Failed to add queue %d for dev %d",					__func__,					q->properties.queue_id,					dqm->dev->id);				return retval;			}		}	} 	return retval;} 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;	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;	struct drm_wedge_task_info *info = NULL;	struct amdgpu_task_info *ti = NULL;	struct kfd_process_device *pdd;	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;	} 	/* reset should be used only in dqm locked queue reset */	if (WARN_ON(dqm->detect_hang_count > 0))		return 0; 	if (!amdgpu_gpu_recovery) {		r = -ENOTRECOVERABLE;		goto fail;	} 	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;	pdd = kfd_get_process_device_data(q->device, q->process);	if (pdd) {		ti = amdgpu_vm_get_task_info_pasid(adev, pdd->pasid);		if (ti) {			amdgpu_vm_print_task_info(adev, ti);			info = &ti->task;		}	} 	dqm->detect_hang_count = num_hung;	/* 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);		if (pdd && pdd->has_reset_queue) {

Lines 1–500 of 4058.