Merge tag 'amd-drm-next-7.3-2026-07-02' of https://gitlab.freedesktop.org/agd5f/linux into drm-next

[airlied: had to reapply
drm/amdgpu: Implement "color format" DRM property by hand to amdgpu_dm_connector.c]

amd-drm-next-7.3-2026-07-02:

amdgpu:
- Queue reset updates
- Initial compute pipe reset support
- Improved boundary checking for bios parsing
- Cleaned up sysfs input parsing
- devcoredump fixes
- RAS updates and rework
- VCN secure submission fixes
- 8K panel fix
- Add display KUnit tests
- Display CRC fixes
- UserQ updates
- Backlight fixes
- Parse panel type info from DisplayID
- Align IP discovery to pci device lifetime
- IOCTL boundary check fixes
- Convert amdgpu_vm_lock_by_pasid() to drm_exec
- Ctx fixes and cleanup
- SOC15 register macro cleanups
- Memory placement fixes for UVD
- Disable KQ support for MI3xx
- GFX9 mode2 reset fix
- BO list cleanup
- Soc24 aborted suspend fix
- Gfx8 soft reset rework
- Enable soft reset on gfx8
- Drop unnecessary BUG() and BUG_ON() in error paths
- Fix power reporting unit conversion
- Improve vbios command table bounds checking
- UVD bounds checking improvements
- VCN bounds checking improvements
- PSR and replay fixes
- DCN 4.2 updates
- Colorop updates
- DC GPIO rework
- ACP fixes
- Fix aperture mapping leak
- Ignore_damage_clips fix
- Fixes for non-4K pages
- JPEG idle check fixes
- Userptr fixes
- GPUVM fixes
- GC 11.7 updates
- SMU 13 fixes

amdkfd:
- Initial compute pipe reset support
- Allow applications to opt out of sigbus on fatal errors
- Fix doorbell/mmio BO cleanup
- Improved CRIU boundary checking
- MQD handling rework
- SMI fixes
- Reset event fixes
- CRIU fixes
- Sysfs teardown fixes
- IOCTL boundary check fixes
- SVM fixes
- Soft IH ring fixes
- Move TBA/TMA from system to device memory

radeon:
- Blit fix for large BOs
- r600 dpm cleanup fix

drm:
- Extract EDID base section header processing into helper
- Parse panel type from DisplayID 2.x Display Parameters

UAPI:
- KFD interface for applications to select sigbus behavior on fatal errors
  Proposed userspace: https://github.com/ROCm/rocm-systems/pull/6190

From: Alex Deucher <alexander.deucher@amd.com>
Link: https://patch.msgid.link/20260702141515.67919-1-alexander.deucher@amd.com
Signed-off-by: Dave Airlie <airlied@redhat.com>
This commit is contained in:
Dave Airlie
2026-07-07 16:47:08 +10:00
376 changed files with 33105 additions and 21341 deletions

View File

@@ -70,7 +70,7 @@ amdgpu-y += amdgpu_device.o amdgpu_reg_access.o amdgpu_doorbell_mgr.o amdgpu_kms
amdgpu_umc.o smu_v11_0_i2c.o amdgpu_fru_eeprom.o amdgpu_rap.o \
amdgpu_fw_attestation.o amdgpu_securedisplay.o \
amdgpu_eeprom.o amdgpu_mca.o amdgpu_psp_ta.o amdgpu_lsdma.o amdgpu_lockdep.o \
amdgpu_ring_mux.o amdgpu_xcp.o amdgpu_seq64.o amdgpu_aca.o amdgpu_dev_coredump.o \
amdgpu_ring_mux.o amdgpu_xcp.o amdgpu_seq64.o amdgpu_dev_coredump.o \
amdgpu_cper.o amdgpu_userq_fence.o amdgpu_eviction_fence.o amdgpu_ip.o
amdgpu-$(CONFIG_PROC_FS) += amdgpu_fdinfo.o

View File

@@ -44,6 +44,7 @@
#include <linux/hashtable.h>
#include <linux/dma-fence.h>
#include <linux/pci.h>
#include <linux/xarray.h>
#include <drm/ttm/ttm_bo.h>
#include <drm/ttm/ttm_placement.h>
@@ -103,7 +104,6 @@
#include "amdgpu_smuio.h"
#include "amdgpu_fdinfo.h"
#include "amdgpu_mca.h"
#include "amdgpu_aca.h"
#include "amdgpu_ras.h"
#include "amdgpu_lockdep.h"
#include "amdgpu_cper.h"
@@ -113,6 +113,7 @@
#include "amdgpu_userq.h"
#include "amdgpu_eviction_fence.h"
#include "amdgpu_ip.h"
#include "amdgpu_sa.h"
#if defined(CONFIG_DRM_AMD_ISP)
#include "amdgpu_isp.h"
#endif
@@ -272,7 +273,6 @@ extern int amdgpu_ptl;
extern uint amdgpu_hdmi_hpd_debounce_delay_ms;
#define AMDGPU_VM_MAX_NUM_CTX 4096
#define AMDGPU_SG_THRESHOLD (256*1024*1024)
#define AMDGPU_WAIT_IDLE_TIMEOUT_IN_MS 3000
#define AMDGPU_MAX_USEC_TIMEOUT 100000 /* 100 ms */
@@ -305,9 +305,10 @@ extern uint amdgpu_hdmi_hpd_debounce_delay_ms;
/* reset mask */
#define AMDGPU_RESET_TYPE_FULL (1 << 0) /* full adapter reset, mode1/mode2/BACO/etc. */
#define AMDGPU_RESET_TYPE_SOFT_RESET (1 << 1) /* IP level soft reset */
#define AMDGPU_RESET_TYPE_SOFT_RECOVERY (1 << 1) /* soft recovery, eg. kill shaders */
#define AMDGPU_RESET_TYPE_PER_QUEUE (1 << 2) /* per queue */
#define AMDGPU_RESET_TYPE_PER_PIPE (1 << 3) /* per pipe */
#define AMDGPU_RESET_TYPE_IP_BLOCK_SOFT_RESET (1 << 4) /* soft-resets an IP block */
/* max cursor sizes (in pixels) */
#define CIK_CURSOR_WIDTH 128
@@ -387,37 +388,6 @@ struct amdgpu_clock {
uint32_t max_pixel_clock;
};
/* sub-allocation manager, it has to be protected by another lock.
* By conception this is an helper for other part of the driver
* like the indirect buffer or semaphore, which both have their
* locking.
*
* Principe is simple, we keep a list of sub allocation in offset
* order (first entry has offset == 0, last entry has the highest
* offset).
*
* When allocating new object we first check if there is room at
* the end total_size - (last_object_offset + last_object_size) >=
* alloc_size. If so we allocate new object there.
*
* When there is not enough room at the end, we start waiting for
* each sub object until we reach object_offset+object_size >=
* alloc_size, this object then become the sub object we return.
*
* Alignment can't be bigger than page size.
*
* Hole are not considered for allocation to keep things simple.
* Assumption is that there won't be hole (all object on same
* alignment).
*/
struct amdgpu_sa_manager {
struct drm_suballoc_manager base;
struct amdgpu_bo *bo;
uint64_t gpu_addr;
void *cpu_ptr;
};
/*
* IRQS.
*/
@@ -446,8 +416,7 @@ struct amdgpu_fpriv {
struct amdgpu_bo_va *prt_va;
struct amdgpu_bo_va *csa_va;
struct amdgpu_bo_va *seq64_va;
struct mutex bo_list_lock;
struct idr bo_list_handles;
struct xarray bo_list_handles;
struct amdgpu_ctx_mgr ctx_mgr;
struct amdgpu_userq_mgr userq_mgr;
@@ -587,8 +556,6 @@ struct amdgpu_asic_funcs {
/* invalidate hdp read cache */
void (*invalidate_hdp)(struct amdgpu_device *adev,
struct amdgpu_ring *ring);
/* check if the asic needs a full reset of if soft reset will work */
bool (*need_full_reset)(struct amdgpu_device *adev);
/* initialize doorbell layout for specific asic*/
void (*init_doorbell_index)(struct amdgpu_device *adev);
/* PCIe bandwidth usage */
@@ -851,6 +818,7 @@ struct amdgpu_device {
struct dev_pm_domain vga_pm_domain;
bool have_disp_power_ref;
bool have_atomics_support;
bool is_sw_smu;
/* BIOS */
bool is_atom_fw;
@@ -1022,9 +990,6 @@ struct amdgpu_device {
/* MCA */
struct amdgpu_mca mca;
/* ACA */
struct amdgpu_aca aca;
/* CPER */
struct amdgpu_cper cper;
@@ -1136,6 +1101,8 @@ struct amdgpu_device {
bool debug_vm_userptr;
bool debug_disable_ce_logs;
bool debug_enable_ce_cs;
bool debug_hibernation_thaw_resume_gpu;
bool debug_disable_ip_block_soft_reset;
/* Protection for the following isolation structure */
struct mutex enforce_isolation_mutex;
@@ -1356,7 +1323,6 @@ int emu_soc_asic_init(struct amdgpu_device *adev);
#define amdgpu_asic_read_bios_from_rom(adev, b, l) (adev)->asic_funcs->read_bios_from_rom((adev), (b), (l))
#define amdgpu_asic_read_register(adev, se, sh, offset, v)((adev)->asic_funcs->read_register((adev), (se), (sh), (offset), (v)))
#define amdgpu_asic_get_config_memsize(adev) (adev)->asic_funcs->get_config_memsize((adev))
#define amdgpu_asic_need_full_reset(adev) (adev)->asic_funcs->need_full_reset((adev))
#define amdgpu_asic_init_doorbell_index(adev) (adev)->asic_funcs->init_doorbell_index((adev))
#define amdgpu_asic_get_pcie_usage(adev, cnt0, cnt1) ((adev)->asic_funcs->get_pcie_usage((adev), (cnt0), (cnt1)))
#define amdgpu_asic_need_reset_on_init(adev) (adev)->asic_funcs->need_reset_on_init((adev))
@@ -1468,6 +1434,8 @@ int amdgpu_enable_vblank_kms(struct drm_crtc *crtc);
void amdgpu_disable_vblank_kms(struct drm_crtc *crtc);
int amdgpu_info_ioctl(struct drm_device *dev, void *data,
struct drm_file *filp);
int amdgpu_proc_options_ioctl(struct drm_device *dev, void *data,
struct drm_file *filp);
/*
* functions used by amdgpu_encoder.c

View File

@@ -1,985 +0,0 @@
/*
* Copyright 2023 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/list.h>
#include "amdgpu.h"
#include "amdgpu_aca.h"
#include "amdgpu_ras.h"
#define ACA_BANK_HWID(type, hwid, mcatype) [ACA_HWIP_TYPE_##type] = {hwid, mcatype}
typedef int bank_handler_t(struct aca_handle *handle, struct aca_bank *bank, enum aca_smu_type type, void *data);
static struct aca_hwip aca_hwid_mcatypes[ACA_HWIP_TYPE_COUNT] = {
ACA_BANK_HWID(SMU, 0x01, 0x01),
ACA_BANK_HWID(PCS_XGMI, 0x50, 0x00),
ACA_BANK_HWID(UMC, 0x96, 0x00),
};
static void aca_banks_init(struct aca_banks *banks)
{
if (!banks)
return;
memset(banks, 0, sizeof(*banks));
INIT_LIST_HEAD(&banks->list);
}
static int aca_banks_add_bank(struct aca_banks *banks, struct aca_bank *bank)
{
struct aca_bank_node *node;
if (!bank)
return -EINVAL;
node = kvzalloc_obj(*node);
if (!node)
return -ENOMEM;
memcpy(&node->bank, bank, sizeof(*bank));
INIT_LIST_HEAD(&node->node);
list_add_tail(&node->node, &banks->list);
banks->nr_banks++;
return 0;
}
static void aca_banks_release(struct aca_banks *banks)
{
struct aca_bank_node *node, *tmp;
if (list_empty(&banks->list))
return;
list_for_each_entry_safe(node, tmp, &banks->list, node) {
list_del(&node->node);
kvfree(node);
banks->nr_banks--;
}
}
static int aca_smu_get_valid_aca_count(struct amdgpu_device *adev, enum aca_smu_type type, u32 *count)
{
struct amdgpu_aca *aca = &adev->aca;
const struct aca_smu_funcs *smu_funcs = aca->smu_funcs;
if (!count)
return -EINVAL;
if (!smu_funcs || !smu_funcs->get_valid_aca_count)
return -EOPNOTSUPP;
return smu_funcs->get_valid_aca_count(adev, type, count);
}
static struct aca_regs_dump {
const char *name;
int reg_idx;
} aca_regs[] = {
{"CONTROL", ACA_REG_IDX_CTL},
{"STATUS", ACA_REG_IDX_STATUS},
{"ADDR", ACA_REG_IDX_ADDR},
{"MISC", ACA_REG_IDX_MISC0},
{"CONFIG", ACA_REG_IDX_CONFIG},
{"IPID", ACA_REG_IDX_IPID},
{"SYND", ACA_REG_IDX_SYND},
{"DESTAT", ACA_REG_IDX_DESTAT},
{"DEADDR", ACA_REG_IDX_DEADDR},
{"CONTROL_MASK", ACA_REG_IDX_CTL_MASK},
};
static void aca_smu_bank_dump(struct amdgpu_device *adev, int idx, int total, struct aca_bank *bank,
struct ras_query_context *qctx)
{
u64 event_id = qctx ? qctx->evid.event_id : RAS_EVENT_INVALID_ID;
int i;
if (adev->debug_disable_ce_logs &&
bank->smu_err_type == ACA_SMU_TYPE_CE &&
!ACA_BANK_ERR_IS_DEFFERED(bank))
return;
RAS_EVENT_LOG(adev, event_id, HW_ERR "Accelerator Check Architecture events logged\n");
/* plus 1 for output format, e.g: ACA[08/08]: xxxx */
for (i = 0; i < ARRAY_SIZE(aca_regs); i++)
RAS_EVENT_LOG(adev, event_id, HW_ERR "ACA[%02d/%02d].%s=0x%016llx\n",
idx + 1, total, aca_regs[i].name, bank->regs[aca_regs[i].reg_idx]);
if (ACA_REG__STATUS__SCRUB(bank->regs[ACA_REG_IDX_STATUS]))
RAS_EVENT_LOG(adev, event_id, HW_ERR "hardware error logged by the scrubber\n");
}
static bool aca_bank_hwip_is_matched(struct aca_bank *bank, enum aca_hwip_type type)
{
struct aca_hwip *hwip;
int hwid, mcatype;
u64 ipid;
if (!bank || type == ACA_HWIP_TYPE_UNKNOW)
return false;
hwip = &aca_hwid_mcatypes[type];
if (!hwip->hwid)
return false;
ipid = bank->regs[ACA_REG_IDX_IPID];
hwid = ACA_REG__IPID__HARDWAREID(ipid);
mcatype = ACA_REG__IPID__MCATYPE(ipid);
return hwip->hwid == hwid && hwip->mcatype == mcatype;
}
static int aca_smu_get_valid_aca_banks(struct amdgpu_device *adev, enum aca_smu_type type,
int start, int count,
struct aca_banks *banks, struct ras_query_context *qctx)
{
struct amdgpu_aca *aca = &adev->aca;
const struct aca_smu_funcs *smu_funcs = aca->smu_funcs;
struct aca_bank bank;
int i, max_count, ret;
if (!count)
return 0;
if (!smu_funcs || !smu_funcs->get_valid_aca_bank)
return -EOPNOTSUPP;
switch (type) {
case ACA_SMU_TYPE_UE:
max_count = smu_funcs->max_ue_bank_count;
break;
case ACA_SMU_TYPE_CE:
max_count = smu_funcs->max_ce_bank_count;
break;
default:
return -EINVAL;
}
if (start + count > max_count)
return -EINVAL;
count = min_t(int, count, max_count);
for (i = 0; i < count; i++) {
memset(&bank, 0, sizeof(bank));
ret = smu_funcs->get_valid_aca_bank(adev, type, start + i, &bank);
if (ret)
return ret;
bank.smu_err_type = type;
/*
* Poison being consumed when injecting a UE while running background workloads,
* which are unexpected.
*/
if (type == ACA_SMU_TYPE_UE &&
ACA_REG__STATUS__POISON(bank.regs[ACA_REG_IDX_STATUS]) &&
!aca_bank_hwip_is_matched(&bank, ACA_HWIP_TYPE_UMC))
continue;
aca_smu_bank_dump(adev, i, count, &bank, qctx);
ret = aca_banks_add_bank(banks, &bank);
if (ret)
return ret;
}
return 0;
}
static bool aca_bank_is_valid(struct aca_handle *handle, struct aca_bank *bank, enum aca_smu_type type)
{
const struct aca_bank_ops *bank_ops = handle->bank_ops;
/* Parse all deferred errors with UMC aca handle */
if (ACA_BANK_ERR_IS_DEFFERED(bank))
return handle->hwip == ACA_HWIP_TYPE_UMC;
if (!aca_bank_hwip_is_matched(bank, handle->hwip))
return false;
if (!bank_ops->aca_bank_is_valid)
return true;
return bank_ops->aca_bank_is_valid(handle, bank, type, handle->data);
}
static struct aca_bank_error *new_bank_error(struct aca_error *aerr, struct aca_bank_info *info)
{
struct aca_bank_error *bank_error;
bank_error = kvzalloc_obj(*bank_error);
if (!bank_error)
return NULL;
INIT_LIST_HEAD(&bank_error->node);
memcpy(&bank_error->info, info, sizeof(*info));
mutex_lock(&aerr->lock);
list_add_tail(&bank_error->node, &aerr->list);
aerr->nr_errors++;
mutex_unlock(&aerr->lock);
return bank_error;
}
static struct aca_bank_error *find_bank_error(struct aca_error *aerr, struct aca_bank_info *info)
{
struct aca_bank_error *bank_error = NULL;
struct aca_bank_info *tmp_info;
bool found = false;
mutex_lock(&aerr->lock);
list_for_each_entry(bank_error, &aerr->list, node) {
tmp_info = &bank_error->info;
if (tmp_info->socket_id == info->socket_id &&
tmp_info->die_id == info->die_id) {
found = true;
goto out_unlock;
}
}
out_unlock:
mutex_unlock(&aerr->lock);
return found ? bank_error : NULL;
}
static void aca_bank_error_remove(struct aca_error *aerr, struct aca_bank_error *bank_error)
{
if (!aerr || !bank_error)
return;
list_del(&bank_error->node);
aerr->nr_errors--;
kvfree(bank_error);
}
static struct aca_bank_error *get_bank_error(struct aca_error *aerr, struct aca_bank_info *info)
{
struct aca_bank_error *bank_error;
if (!aerr || !info)
return NULL;
bank_error = find_bank_error(aerr, info);
if (bank_error)
return bank_error;
return new_bank_error(aerr, info);
}
int aca_error_cache_log_bank_error(struct aca_handle *handle, struct aca_bank_info *info,
enum aca_error_type type, u64 count)
{
struct aca_error_cache *error_cache = &handle->error_cache;
struct aca_bank_error *bank_error;
struct aca_error *aerr;
if (!handle || !info || type >= ACA_ERROR_TYPE_COUNT)
return -EINVAL;
if (!count)
return 0;
aerr = &error_cache->errors[type];
bank_error = get_bank_error(aerr, info);
if (!bank_error)
return -ENOMEM;
bank_error->count += count;
return 0;
}
static int aca_bank_parser(struct aca_handle *handle, struct aca_bank *bank, enum aca_smu_type type)
{
const struct aca_bank_ops *bank_ops = handle->bank_ops;
if (!bank)
return -EINVAL;
if (!bank_ops->aca_bank_parser)
return -EOPNOTSUPP;
return bank_ops->aca_bank_parser(handle, bank, type,
handle->data);
}
static int handler_aca_log_bank_error(struct aca_handle *handle, struct aca_bank *bank,
enum aca_smu_type type, void *data)
{
int ret;
ret = aca_bank_parser(handle, bank, type);
if (ret)
return ret;
return 0;
}
static int aca_dispatch_bank(struct aca_handle_manager *mgr, struct aca_bank *bank,
enum aca_smu_type type, bank_handler_t handler, void *data)
{
struct aca_handle *handle;
int ret;
if (list_empty(&mgr->list))
return 0;
list_for_each_entry(handle, &mgr->list, node) {
if (!aca_bank_is_valid(handle, bank, type))
continue;
ret = handler(handle, bank, type, data);
if (ret)
return ret;
}
return 0;
}
static int aca_dispatch_banks(struct aca_handle_manager *mgr, struct aca_banks *banks,
enum aca_smu_type type, bank_handler_t handler, void *data)
{
struct aca_bank_node *node;
struct aca_bank *bank;
int ret;
if (!mgr || !banks)
return -EINVAL;
/* pre check to avoid unnecessary operations */
if (list_empty(&mgr->list) || list_empty(&banks->list))
return 0;
list_for_each_entry(node, &banks->list, node) {
bank = &node->bank;
ret = aca_dispatch_bank(mgr, bank, type, handler, data);
if (ret)
return ret;
}
return 0;
}
static bool aca_bank_should_update(struct amdgpu_device *adev, enum aca_smu_type type)
{
struct amdgpu_aca *aca = &adev->aca;
bool ret = true;
/*
* Because the UE Valid MCA count will only be cleared after reset,
* in order to avoid repeated counting of the error count,
* the aca bank is only updated once during the gpu recovery stage.
*/
if (type == ACA_SMU_TYPE_UE) {
if (amdgpu_ras_intr_triggered())
ret = atomic_cmpxchg(&aca->ue_update_flag, 0, 1) == 0;
else
atomic_set(&aca->ue_update_flag, 0);
}
return ret;
}
static void aca_banks_generate_cper(struct amdgpu_device *adev,
enum aca_smu_type type,
struct aca_banks *banks,
int count)
{
struct aca_bank_node *node;
struct aca_bank *bank;
int r;
if (!adev->cper.enabled)
return;
if (!banks || !count) {
dev_warn(adev->dev, "fail to generate cper records\n");
return;
}
/* UEs must be encoded into separate CPER entries */
if (type == ACA_SMU_TYPE_UE) {
struct aca_banks de_banks;
aca_banks_init(&de_banks);
list_for_each_entry(node, &banks->list, node) {
bank = &node->bank;
if (bank->aca_err_type == ACA_ERROR_TYPE_DEFERRED) {
r = aca_banks_add_bank(&de_banks, bank);
if (r)
dev_warn(adev->dev, "fail to add de banks, ret = %d\n", r);
} else {
if (amdgpu_cper_generate_ue_record(adev, bank))
dev_warn(adev->dev, "fail to generate ue cper records\n");
}
}
if (!list_empty(&de_banks.list)) {
if (amdgpu_cper_generate_ce_records(adev, &de_banks, de_banks.nr_banks))
dev_warn(adev->dev, "fail to generate de cper records\n");
}
aca_banks_release(&de_banks);
} else {
/*
* SMU_TYPE_CE banks are combined into 1 CPER entries,
* they could be CEs or DEs or both
*/
if (amdgpu_cper_generate_ce_records(adev, banks, count))
dev_warn(adev->dev, "fail to generate ce cper records\n");
}
}
static int aca_banks_update(struct amdgpu_device *adev, enum aca_smu_type type,
bank_handler_t handler, struct ras_query_context *qctx, void *data)
{
struct amdgpu_aca *aca = &adev->aca;
struct aca_banks banks;
u32 count = 0;
int ret;
if (list_empty(&aca->mgr.list))
return 0;
if (!aca_bank_should_update(adev, type))
return 0;
ret = aca_smu_get_valid_aca_count(adev, type, &count);
if (ret)
return ret;
if (!count)
return 0;
aca_banks_init(&banks);
ret = aca_smu_get_valid_aca_banks(adev, type, 0, count, &banks, qctx);
if (ret)
goto err_release_banks;
if (list_empty(&banks.list)) {
ret = 0;
goto err_release_banks;
}
ret = aca_dispatch_banks(&aca->mgr, &banks, type,
handler, data);
if (ret)
goto err_release_banks;
aca_banks_generate_cper(adev, type, &banks, count);
err_release_banks:
aca_banks_release(&banks);
return ret;
}
static int aca_log_aca_error_data(struct aca_bank_error *bank_error, enum aca_error_type type, struct ras_err_data *err_data)
{
struct aca_bank_info *info;
struct amdgpu_smuio_mcm_config_info mcm_info;
u64 count;
if (type >= ACA_ERROR_TYPE_COUNT)
return -EINVAL;
count = bank_error->count;
if (!count)
return 0;
info = &bank_error->info;
mcm_info.die_id = info->die_id;
mcm_info.socket_id = info->socket_id;
switch (type) {
case ACA_ERROR_TYPE_UE:
amdgpu_ras_error_statistic_ue_count(err_data, &mcm_info, count);
break;
case ACA_ERROR_TYPE_CE:
amdgpu_ras_error_statistic_ce_count(err_data, &mcm_info, count);
break;
case ACA_ERROR_TYPE_DEFERRED:
amdgpu_ras_error_statistic_de_count(err_data, &mcm_info, count);
break;
default:
break;
}
return 0;
}
static int aca_log_aca_error(struct aca_handle *handle, enum aca_error_type type, struct ras_err_data *err_data)
{
struct aca_error_cache *error_cache = &handle->error_cache;
struct aca_error *aerr = &error_cache->errors[type];
struct aca_bank_error *bank_error, *tmp;
mutex_lock(&aerr->lock);
if (list_empty(&aerr->list))
goto out_unlock;
list_for_each_entry_safe(bank_error, tmp, &aerr->list, node) {
aca_log_aca_error_data(bank_error, type, err_data);
aca_bank_error_remove(aerr, bank_error);
}
out_unlock:
mutex_unlock(&aerr->lock);
return 0;
}
static int __aca_get_error_data(struct amdgpu_device *adev, struct aca_handle *handle, enum aca_error_type type,
struct ras_err_data *err_data, struct ras_query_context *qctx)
{
enum aca_smu_type smu_type;
int ret;
switch (type) {
case ACA_ERROR_TYPE_UE:
smu_type = ACA_SMU_TYPE_UE;
break;
case ACA_ERROR_TYPE_CE:
case ACA_ERROR_TYPE_DEFERRED:
smu_type = ACA_SMU_TYPE_CE;
break;
default:
return -EINVAL;
}
/* update aca bank to aca source error_cache first */
ret = aca_banks_update(adev, smu_type, handler_aca_log_bank_error, qctx, NULL);
if (ret)
return ret;
/* DEs may contain in CEs or UEs */
if (type != ACA_ERROR_TYPE_DEFERRED)
aca_log_aca_error(handle, ACA_ERROR_TYPE_DEFERRED, err_data);
return aca_log_aca_error(handle, type, err_data);
}
static bool aca_handle_is_valid(struct aca_handle *handle)
{
if (!handle->mask || !list_empty(&handle->node))
return false;
return true;
}
int amdgpu_aca_get_error_data(struct amdgpu_device *adev, struct aca_handle *handle,
enum aca_error_type type, struct ras_err_data *err_data,
struct ras_query_context *qctx)
{
if (!handle || !err_data)
return -EINVAL;
if (aca_handle_is_valid(handle))
return -EOPNOTSUPP;
if ((type < 0) || (!(BIT(type) & handle->mask)))
return 0;
return __aca_get_error_data(adev, handle, type, err_data, qctx);
}
static void aca_error_init(struct aca_error *aerr, enum aca_error_type type)
{
mutex_init(&aerr->lock);
INIT_LIST_HEAD(&aerr->list);
aerr->type = type;
aerr->nr_errors = 0;
}
static void aca_init_error_cache(struct aca_handle *handle)
{
struct aca_error_cache *error_cache = &handle->error_cache;
int type;
for (type = ACA_ERROR_TYPE_UE; type < ACA_ERROR_TYPE_COUNT; type++)
aca_error_init(&error_cache->errors[type], type);
}
static void aca_error_fini(struct aca_error *aerr)
{
struct aca_bank_error *bank_error, *tmp;
mutex_lock(&aerr->lock);
if (list_empty(&aerr->list))
goto out_unlock;
list_for_each_entry_safe(bank_error, tmp, &aerr->list, node)
aca_bank_error_remove(aerr, bank_error);
out_unlock:
mutex_unlock(&aerr->lock);
mutex_destroy(&aerr->lock);
}
static void aca_fini_error_cache(struct aca_handle *handle)
{
struct aca_error_cache *error_cache = &handle->error_cache;
int type;
for (type = ACA_ERROR_TYPE_UE; type < ACA_ERROR_TYPE_COUNT; type++)
aca_error_fini(&error_cache->errors[type]);
}
static int add_aca_handle(struct amdgpu_device *adev, struct aca_handle_manager *mgr, struct aca_handle *handle,
const char *name, const struct aca_info *ras_info, void *data)
{
memset(handle, 0, sizeof(*handle));
handle->adev = adev;
handle->mgr = mgr;
handle->name = name;
handle->hwip = ras_info->hwip;
handle->mask = ras_info->mask;
handle->bank_ops = ras_info->bank_ops;
handle->data = data;
aca_init_error_cache(handle);
INIT_LIST_HEAD(&handle->node);
list_add_tail(&handle->node, &mgr->list);
mgr->nr_handles++;
return 0;
}
static ssize_t aca_sysfs_read(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct aca_handle *handle = container_of(attr, struct aca_handle, aca_attr);
/* NOTE: the aca cache will be auto cleared once read,
* So the driver should unify the query entry point, forward request to ras query interface directly */
return amdgpu_ras_aca_sysfs_read(dev, attr, handle, buf, handle->data);
}
static int add_aca_sysfs(struct amdgpu_device *adev, struct aca_handle *handle)
{
struct device_attribute *aca_attr = &handle->aca_attr;
snprintf(handle->attr_name, sizeof(handle->attr_name) - 1, "aca_%s", handle->name);
aca_attr->show = aca_sysfs_read;
aca_attr->attr.name = handle->attr_name;
aca_attr->attr.mode = S_IRUGO;
sysfs_attr_init(&aca_attr->attr);
return sysfs_add_file_to_group(&adev->dev->kobj,
&aca_attr->attr,
"ras");
}
int amdgpu_aca_add_handle(struct amdgpu_device *adev, struct aca_handle *handle,
const char *name, const struct aca_info *ras_info, void *data)
{
struct amdgpu_aca *aca = &adev->aca;
int ret;
if (!amdgpu_aca_is_enabled(adev))
return 0;
ret = add_aca_handle(adev, &aca->mgr, handle, name, ras_info, data);
if (ret)
return ret;
return add_aca_sysfs(adev, handle);
}
static void remove_aca_handle(struct aca_handle *handle)
{
struct aca_handle_manager *mgr = handle->mgr;
aca_fini_error_cache(handle);
list_del(&handle->node);
mgr->nr_handles--;
}
static void remove_aca_sysfs(struct aca_handle *handle)
{
struct amdgpu_device *adev = handle->adev;
struct device_attribute *aca_attr = &handle->aca_attr;
if (adev->dev->kobj.sd)
sysfs_remove_file_from_group(&adev->dev->kobj,
&aca_attr->attr,
"ras");
}
void amdgpu_aca_remove_handle(struct aca_handle *handle)
{
if (!handle || list_empty(&handle->node))
return;
remove_aca_sysfs(handle);
remove_aca_handle(handle);
}
static int aca_manager_init(struct aca_handle_manager *mgr)
{
INIT_LIST_HEAD(&mgr->list);
mgr->nr_handles = 0;
return 0;
}
static void aca_manager_fini(struct aca_handle_manager *mgr)
{
struct aca_handle *handle, *tmp;
if (list_empty(&mgr->list))
return;
list_for_each_entry_safe(handle, tmp, &mgr->list, node)
amdgpu_aca_remove_handle(handle);
}
bool amdgpu_aca_is_enabled(struct amdgpu_device *adev)
{
return (adev->aca.is_enabled ||
adev->debug_enable_ras_aca);
}
int amdgpu_aca_init(struct amdgpu_device *adev)
{
struct amdgpu_aca *aca = &adev->aca;
int ret;
atomic_set(&aca->ue_update_flag, 0);
ret = aca_manager_init(&aca->mgr);
if (ret)
return ret;
return 0;
}
void amdgpu_aca_fini(struct amdgpu_device *adev)
{
struct amdgpu_aca *aca = &adev->aca;
aca_manager_fini(&aca->mgr);
atomic_set(&aca->ue_update_flag, 0);
}
int amdgpu_aca_reset(struct amdgpu_device *adev)
{
struct amdgpu_aca *aca = &adev->aca;
atomic_set(&aca->ue_update_flag, 0);
return 0;
}
void amdgpu_aca_set_smu_funcs(struct amdgpu_device *adev, const struct aca_smu_funcs *smu_funcs)
{
struct amdgpu_aca *aca = &adev->aca;
WARN_ON(aca->smu_funcs);
aca->smu_funcs = smu_funcs;
}
int aca_bank_info_decode(struct aca_bank *bank, struct aca_bank_info *info)
{
u64 ipid;
u32 instidhi, instidlo;
if (!bank || !info)
return -EINVAL;
ipid = bank->regs[ACA_REG_IDX_IPID];
info->hwid = ACA_REG__IPID__HARDWAREID(ipid);
info->mcatype = ACA_REG__IPID__MCATYPE(ipid);
/*
* Unfied DieID Format: SAASS. A:AID, S:Socket.
* Unfied DieID[4:4] = InstanceId[0:0]
* Unfied DieID[0:3] = InstanceIdHi[0:3]
*/
instidhi = ACA_REG__IPID__INSTANCEIDHI(ipid);
instidlo = ACA_REG__IPID__INSTANCEIDLO(ipid);
info->die_id = ((instidhi >> 2) & 0x03);
info->socket_id = ((instidlo & 0x1) << 2) | (instidhi & 0x03);
return 0;
}
static int aca_bank_get_error_code(struct amdgpu_device *adev, struct aca_bank *bank)
{
struct amdgpu_aca *aca = &adev->aca;
const struct aca_smu_funcs *smu_funcs = aca->smu_funcs;
if (!smu_funcs || !smu_funcs->parse_error_code)
return -EOPNOTSUPP;
return smu_funcs->parse_error_code(adev, bank);
}
int aca_bank_check_error_codes(struct amdgpu_device *adev, struct aca_bank *bank, int *err_codes, int size)
{
int i, error_code;
if (!bank || !err_codes)
return -EINVAL;
error_code = aca_bank_get_error_code(adev, bank);
if (error_code < 0)
return error_code;
for (i = 0; i < size; i++) {
if (err_codes[i] == error_code)
return 0;
}
return -EINVAL;
}
int amdgpu_aca_smu_set_debug_mode(struct amdgpu_device *adev, bool en)
{
struct amdgpu_aca *aca = &adev->aca;
const struct aca_smu_funcs *smu_funcs = aca->smu_funcs;
if (!smu_funcs || !smu_funcs->set_debug_mode)
return -EOPNOTSUPP;
return smu_funcs->set_debug_mode(adev, en);
}
#if defined(CONFIG_DEBUG_FS)
static int amdgpu_aca_smu_debug_mode_set(void *data, u64 val)
{
struct amdgpu_device *adev = (struct amdgpu_device *)data;
int ret;
ret = amdgpu_ras_set_aca_debug_mode(adev, val ? true : false);
if (ret)
return ret;
dev_info(adev->dev, "amdgpu set smu aca debug mode %s success\n", val ? "on" : "off");
return 0;
}
static void aca_dump_entry(struct seq_file *m, struct aca_bank *bank, enum aca_smu_type type, int idx)
{
struct aca_bank_info info;
int i, ret;
ret = aca_bank_info_decode(bank, &info);
if (ret)
return;
seq_printf(m, "aca entry[%d].type: %s\n", idx, type == ACA_SMU_TYPE_UE ? "UE" : "CE");
seq_printf(m, "aca entry[%d].info: socketid:%d aid:%d hwid:0x%03x mcatype:0x%04x\n",
idx, info.socket_id, info.die_id, info.hwid, info.mcatype);
for (i = 0; i < ARRAY_SIZE(aca_regs); i++)
seq_printf(m, "aca entry[%d].regs[%d]: 0x%016llx\n", idx, aca_regs[i].reg_idx, bank->regs[aca_regs[i].reg_idx]);
}
struct aca_dump_context {
struct seq_file *m;
int idx;
};
static int handler_aca_bank_dump(struct aca_handle *handle, struct aca_bank *bank,
enum aca_smu_type type, void *data)
{
struct aca_dump_context *ctx = (struct aca_dump_context *)data;
aca_dump_entry(ctx->m, bank, type, ctx->idx++);
return handler_aca_log_bank_error(handle, bank, type, NULL);
}
static int aca_dump_show(struct seq_file *m, enum aca_smu_type type)
{
struct amdgpu_device *adev = (struct amdgpu_device *)m->private;
struct aca_dump_context context = {
.m = m,
.idx = 0,
};
return aca_banks_update(adev, type, handler_aca_bank_dump, NULL, (void *)&context);
}
static int aca_dump_ce_show(struct seq_file *m, void *unused)
{
return aca_dump_show(m, ACA_SMU_TYPE_CE);
}
static int aca_dump_ce_open(struct inode *inode, struct file *file)
{
return single_open(file, aca_dump_ce_show, inode->i_private);
}
static const struct file_operations aca_ce_dump_debug_fops = {
.owner = THIS_MODULE,
.open = aca_dump_ce_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static int aca_dump_ue_show(struct seq_file *m, void *unused)
{
return aca_dump_show(m, ACA_SMU_TYPE_UE);
}
static int aca_dump_ue_open(struct inode *inode, struct file *file)
{
return single_open(file, aca_dump_ue_show, inode->i_private);
}
static const struct file_operations aca_ue_dump_debug_fops = {
.owner = THIS_MODULE,
.open = aca_dump_ue_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
DEFINE_DEBUGFS_ATTRIBUTE(aca_debug_mode_fops, NULL, amdgpu_aca_smu_debug_mode_set, "%llu\n");
#endif
void amdgpu_aca_smu_debugfs_init(struct amdgpu_device *adev, struct dentry *root)
{
#if defined(CONFIG_DEBUG_FS)
if (!root)
return;
debugfs_create_file("aca_debug_mode", 0200, root, adev, &aca_debug_mode_fops);
debugfs_create_file("aca_ue_dump", 0400, root, adev, &aca_ue_dump_debug_fops);
debugfs_create_file("aca_ce_dump", 0400, root, adev, &aca_ce_dump_debug_fops);
#endif
}

View File

@@ -1,232 +0,0 @@
/*
* Copyright 2023 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.
*
*/
#ifndef __AMDGPU_ACA_H__
#define __AMDGPU_ACA_H__
#include <linux/list.h>
struct ras_err_data;
struct ras_query_context;
#define ACA_MAX_REGS_COUNT (16)
#define ACA_REG_FIELD(x, h, l) (((x) & GENMASK_ULL(h, l)) >> l)
#define ACA_REG__STATUS__VAL(x) ACA_REG_FIELD(x, 63, 63)
#define ACA_REG__STATUS__OVERFLOW(x) ACA_REG_FIELD(x, 62, 62)
#define ACA_REG__STATUS__UC(x) ACA_REG_FIELD(x, 61, 61)
#define ACA_REG__STATUS__EN(x) ACA_REG_FIELD(x, 60, 60)
#define ACA_REG__STATUS__MISCV(x) ACA_REG_FIELD(x, 59, 59)
#define ACA_REG__STATUS__ADDRV(x) ACA_REG_FIELD(x, 58, 58)
#define ACA_REG__STATUS__PCC(x) ACA_REG_FIELD(x, 57, 57)
#define ACA_REG__STATUS__ERRCOREIDVAL(x) ACA_REG_FIELD(x, 56, 56)
#define ACA_REG__STATUS__TCC(x) ACA_REG_FIELD(x, 55, 55)
#define ACA_REG__STATUS__SYNDV(x) ACA_REG_FIELD(x, 53, 53)
#define ACA_REG__STATUS__CECC(x) ACA_REG_FIELD(x, 46, 46)
#define ACA_REG__STATUS__UECC(x) ACA_REG_FIELD(x, 45, 45)
#define ACA_REG__STATUS__DEFERRED(x) ACA_REG_FIELD(x, 44, 44)
#define ACA_REG__STATUS__POISON(x) ACA_REG_FIELD(x, 43, 43)
#define ACA_REG__STATUS__SCRUB(x) ACA_REG_FIELD(x, 40, 40)
#define ACA_REG__STATUS__ERRCOREID(x) ACA_REG_FIELD(x, 37, 32)
#define ACA_REG__STATUS__ADDRLSB(x) ACA_REG_FIELD(x, 29, 24)
#define ACA_REG__STATUS__ERRORCODEEXT(x) ACA_REG_FIELD(x, 21, 16)
#define ACA_REG__STATUS__ERRORCODE(x) ACA_REG_FIELD(x, 15, 0)
#define ACA_REG__IPID__MCATYPE(x) ACA_REG_FIELD(x, 63, 48)
#define ACA_REG__IPID__INSTANCEIDHI(x) ACA_REG_FIELD(x, 47, 44)
#define ACA_REG__IPID__HARDWAREID(x) ACA_REG_FIELD(x, 43, 32)
#define ACA_REG__IPID__INSTANCEIDLO(x) ACA_REG_FIELD(x, 31, 0)
#define ACA_REG__MISC0__VALID(x) ACA_REG_FIELD(x, 63, 63)
#define ACA_REG__MISC0__OVRFLW(x) ACA_REG_FIELD(x, 48, 48)
#define ACA_REG__MISC0__ERRCNT(x) ACA_REG_FIELD(x, 43, 32)
#define ACA_REG__SYND__ERRORINFORMATION(x) ACA_REG_FIELD(x, 17, 0)
/* NOTE: The following codes refers to the smu header file */
#define ACA_EXTERROR_CODE_CE 0x3a
#define ACA_EXTERROR_CODE_FAULT 0x3b
#define ACA_ERROR_UE_MASK BIT_MASK(ACA_ERROR_TYPE_UE)
#define ACA_ERROR_CE_MASK BIT_MASK(ACA_ERROR_TYPE_CE)
#define ACA_ERROR_DEFERRED_MASK BIT_MASK(ACA_ERROR_TYPE_DEFERRED)
#define mmSMNAID_AID0_MCA_SMU 0x03b30400 /* SMN AID AID0 */
#define mmSMNAID_XCD0_MCA_SMU 0x36430400 /* SMN AID XCD0 */
#define mmSMNAID_XCD1_MCA_SMU 0x38430400 /* SMN AID XCD1 */
#define mmSMNXCD_XCD0_MCA_SMU 0x40430400 /* SMN XCD XCD0 */
#define ACA_BANK_ERR_IS_DEFFERED(bank) \
(ACA_REG__STATUS__POISON((bank)->regs[ACA_REG_IDX_STATUS]) || \
ACA_REG__STATUS__DEFERRED((bank)->regs[ACA_REG_IDX_STATUS]))
enum aca_reg_idx {
ACA_REG_IDX_CTL = 0,
ACA_REG_IDX_STATUS = 1,
ACA_REG_IDX_ADDR = 2,
ACA_REG_IDX_MISC0 = 3,
ACA_REG_IDX_CONFIG = 4,
ACA_REG_IDX_IPID = 5,
ACA_REG_IDX_SYND = 6,
ACA_REG_IDX_DESTAT = 8,
ACA_REG_IDX_DEADDR = 9,
ACA_REG_IDX_CTL_MASK = 10,
ACA_REG_IDX_COUNT = 16,
};
enum aca_hwip_type {
ACA_HWIP_TYPE_UNKNOW = -1,
ACA_HWIP_TYPE_PSP = 0,
ACA_HWIP_TYPE_UMC,
ACA_HWIP_TYPE_SMU,
ACA_HWIP_TYPE_PCS_XGMI,
ACA_HWIP_TYPE_COUNT,
};
enum aca_error_type {
ACA_ERROR_TYPE_INVALID = -1,
ACA_ERROR_TYPE_UE = 0,
ACA_ERROR_TYPE_CE,
ACA_ERROR_TYPE_DEFERRED,
ACA_ERROR_TYPE_COUNT
};
enum aca_smu_type {
ACA_SMU_TYPE_INVALID = -1,
ACA_SMU_TYPE_UE = 0,
ACA_SMU_TYPE_CE,
ACA_SMU_TYPE_COUNT,
};
struct aca_hwip {
int hwid;
int mcatype;
};
struct aca_bank {
enum aca_error_type aca_err_type;
enum aca_smu_type smu_err_type;
u64 regs[ACA_MAX_REGS_COUNT];
};
struct aca_bank_node {
struct aca_bank bank;
struct list_head node;
};
struct aca_banks {
int nr_banks;
struct list_head list;
};
struct aca_bank_info {
int die_id;
int socket_id;
int hwid;
int mcatype;
};
struct aca_bank_error {
struct list_head node;
struct aca_bank_info info;
u64 count;
};
struct aca_error {
struct list_head list;
struct mutex lock;
enum aca_error_type type;
int nr_errors;
};
struct aca_handle_manager {
struct list_head list;
int nr_handles;
};
struct aca_error_cache {
struct aca_error errors[ACA_ERROR_TYPE_COUNT];
};
struct aca_handle {
struct list_head node;
enum aca_hwip_type hwip;
struct amdgpu_device *adev;
struct aca_handle_manager *mgr;
struct aca_error_cache error_cache;
const struct aca_bank_ops *bank_ops;
struct device_attribute aca_attr;
char attr_name[64];
const char *name;
u32 mask;
void *data;
};
struct aca_bank_ops {
int (*aca_bank_parser)(struct aca_handle *handle, struct aca_bank *bank, enum aca_smu_type type, void *data);
bool (*aca_bank_is_valid)(struct aca_handle *handle, struct aca_bank *bank, enum aca_smu_type type,
void *data);
};
struct aca_smu_funcs {
int max_ue_bank_count;
int max_ce_bank_count;
int (*set_debug_mode)(struct amdgpu_device *adev, bool enable);
int (*get_valid_aca_count)(struct amdgpu_device *adev, enum aca_smu_type type, u32 *count);
int (*get_valid_aca_bank)(struct amdgpu_device *adev, enum aca_smu_type type, int idx, struct aca_bank *bank);
int (*parse_error_code)(struct amdgpu_device *adev, struct aca_bank *bank);
};
struct amdgpu_aca {
struct aca_handle_manager mgr;
const struct aca_smu_funcs *smu_funcs;
atomic_t ue_update_flag;
bool is_enabled;
};
struct aca_info {
enum aca_hwip_type hwip;
const struct aca_bank_ops *bank_ops;
u32 mask;
};
int amdgpu_aca_init(struct amdgpu_device *adev);
void amdgpu_aca_fini(struct amdgpu_device *adev);
int amdgpu_aca_reset(struct amdgpu_device *adev);
void amdgpu_aca_set_smu_funcs(struct amdgpu_device *adev, const struct aca_smu_funcs *smu_funcs);
bool amdgpu_aca_is_enabled(struct amdgpu_device *adev);
int aca_bank_info_decode(struct aca_bank *bank, struct aca_bank_info *info);
int aca_bank_check_error_codes(struct amdgpu_device *adev, struct aca_bank *bank, int *err_codes, int size);
int amdgpu_aca_add_handle(struct amdgpu_device *adev, struct aca_handle *handle,
const char *name, const struct aca_info *aca_info, void *data);
void amdgpu_aca_remove_handle(struct aca_handle *handle);
int amdgpu_aca_get_error_data(struct amdgpu_device *adev, struct aca_handle *handle,
enum aca_error_type type, struct ras_err_data *err_data,
struct ras_query_context *qctx);
int amdgpu_aca_smu_set_debug_mode(struct amdgpu_device *adev, bool en);
void amdgpu_aca_smu_debugfs_init(struct amdgpu_device *adev, struct dentry *root);
int aca_error_cache_log_bank_error(struct aca_handle *handle, struct aca_bank_info *info,
enum aca_error_type type, u64 count);
#endif

View File

@@ -140,13 +140,15 @@ static struct amdgpu_acpi_priv {
* @atif: atif structure
* @function: the ATIF function to execute
* @params: ATIF function params
* @min_size: minimum size of the expected output buffer in bytes
*
* Executes the requested ATIF function (all asics).
* Returns a pointer to the acpi output buffer.
*/
static union acpi_object *amdgpu_atif_call(struct amdgpu_atif *atif,
int function,
struct acpi_buffer *params)
struct acpi_buffer *params,
size_t min_size)
{
acpi_status status;
union acpi_object *obj;
@@ -189,6 +191,28 @@ static union acpi_object *amdgpu_atif_call(struct amdgpu_atif *atif,
return NULL;
}
if (obj->buffer.length < sizeof(u16)) {
DRM_DEBUG_DRIVER("ATIF buffer too small to hold size field: %u\n",
obj->buffer.length);
kfree(obj);
return NULL;
}
if (obj->buffer.length < *(u16 *)obj->buffer.pointer) {
DRM_DEBUG_DRIVER("ATIF buffer length mismatch: reported %u, actual %u\n",
*(u16 *)obj->buffer.pointer,
obj->buffer.length);
kfree(obj);
return NULL;
}
if (*(u16 *)obj->buffer.pointer < min_size) {
DRM_DEBUG_DRIVER("ATIF buffer too small: expected %zu, got %u\n",
min_size, *(u16 *)obj->buffer.pointer);
kfree(obj);
return NULL;
}
return obj;
}
@@ -251,19 +275,14 @@ int amdgpu_atif_verify_interface(struct amdgpu_atif *atif)
size_t size;
int err = 0;
info = amdgpu_atif_call(atif, ATIF_FUNCTION_VERIFY_INTERFACE, NULL);
info = amdgpu_atif_call(atif, ATIF_FUNCTION_VERIFY_INTERFACE, NULL,
sizeof(output));
if (!info)
return -EIO;
memset(&output, 0, sizeof(output));
size = *(u16 *) info->buffer.pointer;
if (size < 12) {
DRM_INFO("ATIF buffer is too small: %zu\n", size);
err = -EINVAL;
goto out;
}
size = min(sizeof(output), size);
size = min(sizeof(output), (size_t)*(u16 *)info->buffer.pointer);
memcpy(&output, info->buffer.pointer, size);
@@ -273,7 +292,6 @@ int amdgpu_atif_verify_interface(struct amdgpu_atif *atif)
amdgpu_atif_parse_notification(&atif->notifications, output.notification_mask);
amdgpu_atif_parse_functions(&atif->functions, output.function_bits);
out:
kfree(info);
return err;
}
@@ -299,20 +317,14 @@ int amdgpu_atif_get_notification_params(struct amdgpu_atif *atif)
int err = 0;
info = amdgpu_atif_call(atif, ATIF_FUNCTION_GET_SYSTEM_PARAMETERS,
NULL);
NULL, offsetof(struct atif_system_params, command_code));
if (!info) {
err = -EIO;
goto out;
}
size = *(u16 *) info->buffer.pointer;
if (size < 10) {
err = -EINVAL;
goto out;
}
memset(&params, 0, sizeof(params));
size = min(sizeof(params), size);
size = min(sizeof(params), (size_t)*(u16 *)info->buffer.pointer);
memcpy(&params, info->buffer.pointer, size);
DRM_DEBUG_DRIVER("SYSTEM_PARAMS: mask = %#x, flags = %#x\n",
@@ -376,20 +388,14 @@ int amdgpu_atif_query_backlight_caps(struct amdgpu_atif *atif)
info = amdgpu_atif_call(atif,
ATIF_FUNCTION_QUERY_BRIGHTNESS_TRANSFER_CHARACTERISTICS,
&params);
&params, offsetof(struct atif_qbtc_output, data_points));
if (!info) {
err = -EIO;
goto out;
}
size = *(u16 *) info->buffer.pointer;
if (size < 10) {
err = -EINVAL;
goto out;
}
memset(&characteristics, 0, sizeof(characteristics));
size = min(sizeof(characteristics), size);
size = min(sizeof(characteristics), (size_t)*(u16 *)info->buffer.pointer);
memcpy(&characteristics, info->buffer.pointer, size);
atif->backlight_caps.caps_valid = true;
@@ -427,24 +433,18 @@ static int amdgpu_atif_get_sbios_requests(struct amdgpu_atif *atif,
int count = 0;
info = amdgpu_atif_call(atif, ATIF_FUNCTION_GET_SYSTEM_BIOS_REQUESTS,
NULL);
NULL, sizeof(*req));
if (!info)
return -EIO;
size = *(u16 *)info->buffer.pointer;
if (size < 0xd) {
count = -EINVAL;
goto out;
}
memset(req, 0, sizeof(*req));
size = min(sizeof(*req), size);
size = min(sizeof(*req), (size_t)*(u16 *)info->buffer.pointer);
memcpy(req, info->buffer.pointer, size);
DRM_DEBUG_DRIVER("SBIOS pending requests: %#x\n", req->pending);
count = hweight32(req->pending);
out:
kfree(info);
return count;
}

View File

@@ -957,3 +957,17 @@ int amdgpu_amdkfd_config_sq_perfmon(struct amdgpu_device *adev, uint32_t xcp_id,
return r;
}
/* Reset an MES queue */
int amdgpu_amdkfd_reset_mes_queue(struct amdgpu_device *adev,
uint32_t node_id,
int queue_type,
int pipe, int queue,
unsigned int db)
{
if (!adev->kfd.init_complete)
return 0;
return kgd2kfd_reset_mes_queue(adev->kfd.dev, node_id, queue_type,
pipe, queue, db);
}

View File

@@ -210,6 +210,7 @@ int amdgpu_amdkfd_evict_userptr(struct mmu_interval_notifier *mni,
int amdgpu_amdkfd_bo_validate_and_fence(struct amdgpu_bo *bo,
uint32_t domain,
struct dma_fence *fence);
int amdgpu_amdkfd_set_sigbus_delay(struct task_struct *task, u32 ms);
#else
static inline
bool amdkfd_fence_check_mm(struct dma_fence *f, struct mm_struct *mm)
@@ -241,6 +242,11 @@ int amdgpu_amdkfd_bo_validate_and_fence(struct amdgpu_bo *bo,
{
return 0;
}
static inline
int amdgpu_amdkfd_set_sigbus_delay(struct task_struct *task, u32 ms)
{
return -EOPNOTSUPP;
}
#endif
/* Shared API */
int amdgpu_amdkfd_alloc_kernel_mem(struct amdgpu_device *adev, size_t size,
@@ -275,7 +281,11 @@ int amdgpu_amdkfd_stop_sched(struct amdgpu_device *adev, uint32_t node_id);
int amdgpu_amdkfd_config_sq_perfmon(struct amdgpu_device *adev, uint32_t xcp_id,
bool core_override_enable, bool reg_override_enable, bool perfmon_override_enable);
bool amdgpu_amdkfd_compute_active(struct amdgpu_device *adev, uint32_t node_id);
int amdgpu_amdkfd_reset_mes_queue(struct amdgpu_device *adev,
uint32_t node_id,
int queue_type,
int pipe, int queue,
unsigned int db);
/* Read user wptr from a specified user address space with page fault
* disabled. The memory must be pinned and mapped to the hardware when
@@ -326,9 +336,9 @@ int amdgpu_amdkfd_gpuvm_unmap_memory_from_gpu(
int amdgpu_amdkfd_gpuvm_dmaunmap_mem(struct kgd_mem *mem, void *drm_priv);
int amdgpu_amdkfd_gpuvm_sync_memory(
struct amdgpu_device *adev, struct kgd_mem *mem, bool intr);
int amdgpu_amdkfd_gpuvm_map_gtt_bo_to_kernel(struct kgd_mem *mem,
void **kptr, uint64_t *size);
void amdgpu_amdkfd_gpuvm_unmap_gtt_bo_from_kernel(struct kgd_mem *mem);
int amdgpu_amdkfd_gpuvm_map_bo_to_kernel(struct kgd_mem *mem, void **kptr,
u64 *size, u32 domain);
void amdgpu_amdkfd_gpuvm_unmap_bo_from_kernel(struct kgd_mem *mem);
int amdgpu_amdkfd_map_gtt_bo_to_gart(struct amdgpu_bo *bo, struct amdgpu_bo **bo_gart);
@@ -446,6 +456,9 @@ bool kgd2kfd_vmfault_fast_path(struct amdgpu_device *adev, struct amdgpu_iv_entr
bool retry_fault);
void kgd2kfd_lock_kfd(void);
void kgd2kfd_teardown_processes(struct amdgpu_device *adev);
int kgd2kfd_reset_mes_queue(struct kfd_dev *kfd, uint32_t node_id,
int queue_type, int pipe, int queue,
unsigned int db);
#else
static inline int kgd2kfd_init(void)
@@ -576,5 +589,12 @@ static inline void kgd2kfd_teardown_processes(struct amdgpu_device *adev)
{
}
static inline int kgd2kfd_reset_mes_queue(struct kfd_dev *kfd, uint32_t node_id,
int queue_type, int pipe, int queue,
unsigned int db)
{
return 0;
}
#endif
#endif /* AMDGPU_AMDKFD_H_INCLUDED */

View File

@@ -530,6 +530,66 @@ static uint32_t kgd_v9_4_3_ptl_ctrl(struct amdgpu_device *adev,
ptl_state, fmt1, fmt2);
}
static int kgd_gfx_v9_4_3_hqd_sdma_get_counter(struct amdgpu_device *adev,
void *mqd, uint32_t num_sdma_queues_per_eng,
uint64_t *val)
{
struct v9_sdma_mqd *m = get_sdma_mqd(mqd);
uint32_t sdma_rlc_reg_offset = 0;
uint32_t sdma_rlc_rb_cntl;
uint32_t engine_id, queue_id;
uint32_t engines = adev->sdma.num_instances;
uint32_t sdma_rlcx_rb_base, sdma_rlcx_rb_base_hi;
bool found = false;
if (!m)
return -EINVAL;
if (((amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 4, 3) ||
amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 4, 4)) &&
adev->gfx.mec_fw_version < 194) ||
(amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 5, 0) &&
adev->gfx.mec_fw_version < 44)) {
pr_warn_once("MEC FW doesn't support SDMA counter!\n");
return -EOPNOTSUPP;
}
/* SDMA doesn't support over-subscription, there must be
* a HQD associated with a MQD, so found must be true in
* the finding loop.
*/
for (engine_id = 0; engine_id < engines && !found; engine_id++) {
for (queue_id = 0; queue_id < num_sdma_queues_per_eng; queue_id++) {
sdma_rlc_reg_offset = get_sdma_rlc_reg_offset(adev,
engine_id, queue_id);
sdma_rlcx_rb_base = RREG32(sdma_rlc_reg_offset +
regSDMA_RLC0_RB_BASE);
sdma_rlcx_rb_base_hi = RREG32(sdma_rlc_reg_offset +
regSDMA_RLC0_RB_BASE_HI);
if (m->sdmax_rlcx_rb_base == sdma_rlcx_rb_base &&
m->sdmax_rlcx_rb_base_hi == sdma_rlcx_rb_base_hi) {
found = true;
break;
}
}
}
sdma_rlc_rb_cntl = RREG32(sdma_rlc_reg_offset + regSDMA_RLC0_RB_CNTL);
/* Read sdma activity counter from utilization register
* if hw queue is enabled, otherwise read from MQD.
*/
if (sdma_rlc_rb_cntl & SDMA_RLC0_RB_CNTL__RB_ENABLE_MASK)
*val = (uint64_t)RREG32(sdma_rlc_reg_offset + regSDMA_RLC0_UTILIZATION_HI) << 32 |
RREG32(sdma_rlc_reg_offset + regSDMA_RLC0_UTILIZATION_LO);
else
*val = (uint64_t)m->sdmax_rlcx_utilization_hi << 32 |
m->sdmax_rlcx_utilization_lo;
return 0;
}
const struct kfd2kgd_calls gc_9_4_3_kfd2kgd = {
.program_sh_mem_settings = kgd_gfx_v9_program_sh_mem_settings,
.set_pasid_vmid_mapping = kgd_gfx_v9_4_3_set_pasid_vmid_mapping,
@@ -566,5 +626,6 @@ const struct kfd2kgd_calls gc_9_4_3_kfd2kgd = {
.hqd_get_pq_addr = kgd_gfx_v9_hqd_get_pq_addr,
.hqd_reset = kgd_gfx_v9_hqd_reset,
.hqd_sdma_get_doorbell = kgd_gfx_v9_4_3_hqd_sdma_get_doorbell,
.ptl_ctrl = kgd_v9_4_3_ptl_ctrl
.ptl_ctrl = kgd_v9_4_3_ptl_ctrl,
.hqd_sdma_get_counter = kgd_gfx_v9_4_3_hqd_sdma_get_counter
};

View File

@@ -2271,11 +2271,14 @@ int amdgpu_amdkfd_map_gtt_bo_to_gart(struct amdgpu_bo *bo, struct amdgpu_bo **bo
return ret;
}
/** amdgpu_amdkfd_gpuvm_map_gtt_bo_to_kernel() - Map a GTT BO for kernel CPU access
/** amdgpu_amdkfd_gpuvm_map_bo_to_kernel() - Map GTT or VRAM BO for kernel CPU access
*
* @mem: Buffer object to be mapped for CPU access
* @kptr[out]: pointer in kernel CPU address space
* @size[out]: size of the buffer
* @domain[IN]: domain for pinning (AMDGPU_GEM_DOMAIN_GTT, AMDGPU_GEM_DOMAIN_VRAM,
* or their combination to let the driver choose). CPU visibility is
* automatically enforced by amdgpu_bo_pin()
*
* Pins the BO and maps it for kernel CPU access. The eviction fence is removed
* from the BO, since pinned BOs cannot be evicted. The bo must remain on the
@@ -2284,8 +2287,8 @@ int amdgpu_amdkfd_map_gtt_bo_to_gart(struct amdgpu_bo *bo, struct amdgpu_bo **bo
*
* Return: 0 on success, error code on failure
*/
int amdgpu_amdkfd_gpuvm_map_gtt_bo_to_kernel(struct kgd_mem *mem,
void **kptr, uint64_t *size)
int amdgpu_amdkfd_gpuvm_map_bo_to_kernel(struct kgd_mem *mem, void **kptr,
u64 *size, u32 domain)
{
int ret;
struct amdgpu_bo *bo = mem->bo;
@@ -2295,6 +2298,11 @@ int amdgpu_amdkfd_gpuvm_map_gtt_bo_to_kernel(struct kgd_mem *mem,
return -EINVAL;
}
if (!(domain & (AMDGPU_GEM_DOMAIN_GTT | AMDGPU_GEM_DOMAIN_VRAM))) {
pr_debug("Invalid domain 0x%x for kernel mapping\n", domain);
return -EINVAL;
}
mutex_lock(&mem->process_info->lock);
ret = amdgpu_bo_reserve(bo, true);
@@ -2303,7 +2311,7 @@ int amdgpu_amdkfd_gpuvm_map_gtt_bo_to_kernel(struct kgd_mem *mem,
goto bo_reserve_failed;
}
ret = amdgpu_bo_pin(bo, AMDGPU_GEM_DOMAIN_GTT);
ret = amdgpu_bo_pin(bo, domain);
if (ret) {
pr_err("Failed to pin bo. ret %d\n", ret);
goto pin_failed;
@@ -2336,7 +2344,7 @@ int amdgpu_amdkfd_gpuvm_map_gtt_bo_to_kernel(struct kgd_mem *mem,
return ret;
}
/** amdgpu_amdkfd_gpuvm_map_gtt_bo_to_kernel() - Unmap a GTT BO for kernel CPU access
/** amdgpu_amdkfd_gpuvm_unmap_bo_from_kernel() - Unmap GTT or VRAM BO for kernel CPU access
*
* @mem: Buffer object to be unmapped for CPU access
*
@@ -2344,7 +2352,7 @@ int amdgpu_amdkfd_gpuvm_map_gtt_bo_to_kernel(struct kgd_mem *mem,
* eviction fence, so this function should only be used for cleanup before the
* BO is destroyed.
*/
void amdgpu_amdkfd_gpuvm_unmap_gtt_bo_from_kernel(struct kgd_mem *mem)
void amdgpu_amdkfd_gpuvm_unmap_bo_from_kernel(struct kgd_mem *mem)
{
struct amdgpu_bo *bo = mem->bo;

View File

@@ -1923,7 +1923,7 @@ int amdgpu_atombios_init(struct amdgpu_device *adev)
atom_card_info->pll_read = cail_pll_read;
atom_card_info->pll_write = cail_pll_write;
adev->mode_info.atom_context = amdgpu_atom_parse(atom_card_info, adev->bios);
adev->mode_info.atom_context = amdgpu_atom_parse(atom_card_info, adev->bios, adev->bios_size);
if (!adev->mode_info.atom_context) {
amdgpu_atombios_fini(adev);
return -ENOMEM;

View File

@@ -89,6 +89,15 @@ bool amdgpu_is_atpx_hybrid(void)
return amdgpu_atpx_priv.atpx.is_hybrid;
}
static bool amdgpu_atpx_buffer_validate(const union acpi_object *obj,
size_t min_size)
{
return obj && obj->type == ACPI_TYPE_BUFFER &&
obj->buffer.length >= sizeof(u16) &&
obj->buffer.length >= *(u16 *)obj->buffer.pointer &&
*(u16 *)obj->buffer.pointer >= min_size;
}
/**
* amdgpu_atpx_call - call an ATPX method
*
@@ -179,15 +188,15 @@ static int amdgpu_atpx_validate(struct amdgpu_atpx *atpx)
if (!info)
return -EIO;
memset(&output, 0, sizeof(output));
size = *(u16 *) info->buffer.pointer;
if (size < 10) {
pr_err("ATPX buffer is too small: %zu\n", size);
if (!amdgpu_atpx_buffer_validate(info, sizeof(output))) {
pr_err("Invalid ATPX GET_PX_PARAMETERS response\n");
kfree(info);
return -EINVAL;
}
size = min(sizeof(output), size);
memset(&output, 0, sizeof(output));
size = min(sizeof(output), (size_t)*(u16 *)info->buffer.pointer);
memcpy(&output, info->buffer.pointer, size);
@@ -258,15 +267,15 @@ static int amdgpu_atpx_verify_interface(struct amdgpu_atpx *atpx)
if (!info)
return -EIO;
memset(&output, 0, sizeof(output));
size = *(u16 *) info->buffer.pointer;
if (size < 8) {
pr_err("ATPX buffer is too small: %zu\n", size);
if (!amdgpu_atpx_buffer_validate(info, sizeof(output))) {
pr_err("Invalid ATPX VERIFY_INTERFACE response\n");
err = -EINVAL;
goto out;
}
size = min(sizeof(output), size);
memset(&output, 0, sizeof(output));
size = min(sizeof(output), (size_t)*(u16 *)info->buffer.pointer);
memcpy(&output, info->buffer.pointer, size);

View File

@@ -296,8 +296,14 @@ static int amdgpu_atrm_call(acpi_handle atrm_handle, uint8_t *bios,
}
obj = (union acpi_object *)buffer.pointer;
memcpy(bios+offset, obj->buffer.pointer, obj->buffer.length);
len = obj->buffer.length;
if (!obj || obj->type != ACPI_TYPE_BUFFER) {
DRM_ERROR("ATRM returned an invalid object\n");
kfree(buffer.pointer);
return -EINVAL;
}
len = min_t(size_t, obj->buffer.length, len);
memcpy(bios+offset, obj->buffer.pointer, len);
kfree(buffer.pointer);
return len;
}

View File

@@ -38,14 +38,6 @@
#define AMDGPU_BO_LIST_NUM_BUCKETS (AMDGPU_BO_LIST_MAX_PRIORITY + 1)
#define AMDGPU_BO_LIST_MAX_ENTRIES (128 * 1024)
static void amdgpu_bo_list_free_rcu(struct rcu_head *rcu)
{
struct amdgpu_bo_list *list = container_of(rcu, struct amdgpu_bo_list,
rhead);
mutex_destroy(&list->bo_list_mutex);
kvfree(list);
}
static void amdgpu_bo_list_free(struct kref *ref)
{
struct amdgpu_bo_list *list = container_of(ref, struct amdgpu_bo_list,
@@ -54,7 +46,8 @@ static void amdgpu_bo_list_free(struct kref *ref)
amdgpu_bo_list_for_each_entry(e, list)
amdgpu_bo_unref(&e->bo);
call_rcu(&list->rhead, amdgpu_bo_list_free_rcu);
kvfree(list);
}
static int amdgpu_bo_list_entry_cmp(const void *_a, const void *_b)
@@ -66,9 +59,9 @@ static int amdgpu_bo_list_entry_cmp(const void *_a, const void *_b)
return (int)a->priority - (int)b->priority;
}
int amdgpu_bo_list_create(struct amdgpu_device *adev, struct drm_file *filp,
struct drm_amdgpu_bo_list_entry *info,
size_t num_entries, struct amdgpu_bo_list **result)
struct amdgpu_bo_list *
amdgpu_bo_list_create(struct amdgpu_device *adev, struct drm_file *filp,
struct drm_amdgpu_bo_list_entry *info, size_t num_entries)
{
unsigned last_entry = 0, first_userptr = num_entries;
struct amdgpu_bo_list_entry *array;
@@ -79,7 +72,7 @@ int amdgpu_bo_list_create(struct amdgpu_device *adev, struct drm_file *filp,
list = kvzalloc_flex(*list, entries, num_entries);
if (!list)
return -ENOMEM;
return ERR_PTR(-ENOMEM);
kref_init(&list->refcount);
@@ -134,9 +127,7 @@ int amdgpu_bo_list_create(struct amdgpu_device *adev, struct drm_file *filp,
trace_amdgpu_cs_bo_status(list->num_entries, total_size);
mutex_init(&list->bo_list_mutex);
*result = list;
return 0;
return list;
error_free:
for (i = 0; i < last_entry; ++i)
@@ -144,150 +135,125 @@ int amdgpu_bo_list_create(struct amdgpu_device *adev, struct drm_file *filp,
for (i = first_userptr; i < num_entries; ++i)
amdgpu_bo_unref(&array[i].bo);
kvfree(list);
return r;
return ERR_PTR(r);
}
static void amdgpu_bo_list_destroy(struct amdgpu_fpriv *fpriv, int id)
struct amdgpu_bo_list *amdgpu_bo_list_get(struct amdgpu_fpriv *fpriv, u32 id)
{
struct amdgpu_bo_list *list;
mutex_lock(&fpriv->bo_list_lock);
list = idr_remove(&fpriv->bo_list_handles, id);
mutex_unlock(&fpriv->bo_list_lock);
xa_lock(&fpriv->bo_list_handles);
list = xa_load(&fpriv->bo_list_handles, id);
if (list)
kref_put(&list->refcount, amdgpu_bo_list_free);
}
kref_get(&list->refcount);
else
list = ERR_PTR(-ENOENT);
xa_unlock(&fpriv->bo_list_handles);
int amdgpu_bo_list_get(struct amdgpu_fpriv *fpriv, int id,
struct amdgpu_bo_list **result)
{
rcu_read_lock();
*result = idr_find(&fpriv->bo_list_handles, id);
if (*result && kref_get_unless_zero(&(*result)->refcount)) {
rcu_read_unlock();
return 0;
}
rcu_read_unlock();
*result = NULL;
return -ENOENT;
return list;
}
void amdgpu_bo_list_put(struct amdgpu_bo_list *list)
{
kref_put(&list->refcount, amdgpu_bo_list_free);
if (list)
kref_put(&list->refcount, amdgpu_bo_list_free);
}
int amdgpu_bo_create_list_entry_array(struct drm_amdgpu_bo_list_in *in,
struct drm_amdgpu_bo_list_entry **info_param)
struct drm_amdgpu_bo_list_entry *
amdgpu_bo_create_list_entry_array(struct drm_amdgpu_bo_list_in *in)
{
const uint32_t info_size = sizeof(struct drm_amdgpu_bo_list_entry);
const void __user *uptr = u64_to_user_ptr(in->bo_info_ptr);
const uint32_t bo_info_size = in->bo_info_size;
const uint32_t bo_number = in->bo_number;
struct drm_amdgpu_bo_list_entry *info;
if (bo_number > AMDGPU_BO_LIST_MAX_ENTRIES)
return -EINVAL;
return ERR_PTR(-EINVAL);
/* copy the handle array from userspace to a kernel buffer */
if (likely(info_size == bo_info_size)) {
info = vmemdup_array_user(uptr, bo_number, info_size);
if (IS_ERR(info))
return PTR_ERR(info);
} else {
const uint32_t bytes = min(bo_info_size, info_size);
unsigned i;
if (in->bo_info_size != sizeof(struct drm_amdgpu_bo_list_entry))
return ERR_PTR(-EINVAL);
info = kvmalloc_array(bo_number, info_size, GFP_KERNEL);
if (!info)
return -ENOMEM;
memset(info, 0, bo_number * info_size);
for (i = 0; i < bo_number; ++i, uptr += bo_info_size) {
if (copy_from_user(&info[i], uptr, bytes)) {
kvfree(info);
return -EFAULT;
}
}
}
*info_param = info;
return 0;
return vmemdup_array_user(uptr, bo_number,
sizeof(struct drm_amdgpu_bo_list_entry));
}
int amdgpu_bo_list_ioctl(struct drm_device *dev, void *data,
struct drm_file *filp)
{
struct amdgpu_device *adev = drm_to_adev(dev);
struct amdgpu_fpriv *fpriv = filp->driver_priv;
struct amdgpu_device *adev = drm_to_adev(dev);
struct amdgpu_bo_list *list, *prev, *curr;
union drm_amdgpu_bo_list *args = data;
uint32_t handle = args->in.list_handle;
struct drm_amdgpu_bo_list_entry *info = NULL;
struct amdgpu_bo_list *list, *old;
struct drm_amdgpu_bo_list_entry *info;
int r;
r = amdgpu_bo_create_list_entry_array(&args->in, &info);
if (r)
return r;
switch (args->in.operation) {
case AMDGPU_BO_LIST_OP_CREATE:
r = amdgpu_bo_list_create(adev, filp, info, args->in.bo_number,
&list);
if (r)
goto error_free;
case AMDGPU_BO_LIST_OP_UPDATE:
info = amdgpu_bo_create_list_entry_array(&args->in);
if (IS_ERR(info))
return PTR_ERR(info);
mutex_lock(&fpriv->bo_list_lock);
r = idr_alloc(&fpriv->bo_list_handles, list, 1, 0, GFP_KERNEL);
mutex_unlock(&fpriv->bo_list_lock);
if (r < 0) {
goto error_put_list;
}
list = amdgpu_bo_list_create(adev, filp, info,
args->in.bo_number);
kvfree(info);
if (IS_ERR(list))
return PTR_ERR(list);
handle = r;
break;
case AMDGPU_BO_LIST_OP_DESTROY:
amdgpu_bo_list_destroy(fpriv, handle);
list = xa_erase(&fpriv->bo_list_handles, handle);
amdgpu_bo_list_put(list);
handle = 0;
break;
case AMDGPU_BO_LIST_OP_UPDATE:
r = amdgpu_bo_list_create(adev, filp, info, args->in.bo_number,
&list);
if (r)
goto error_free;
mutex_lock(&fpriv->bo_list_lock);
old = idr_replace(&fpriv->bo_list_handles, list, handle);
mutex_unlock(&fpriv->bo_list_lock);
if (IS_ERR(old)) {
r = PTR_ERR(old);
goto error_put_list;
}
amdgpu_bo_list_put(old);
break;
default:
r = -EINVAL;
goto error_free;
return -EINVAL;
};
switch (args->in.operation) {
case AMDGPU_BO_LIST_OP_CREATE:
r = xa_alloc(&fpriv->bo_list_handles, &handle, list,
xa_limit_32b, GFP_KERNEL);
if (r)
goto error_put_list;
break;
case AMDGPU_BO_LIST_OP_UPDATE:
curr = xa_load(&fpriv->bo_list_handles, handle);
if (!curr) {
r = -ENOENT;
goto error_put_list;
}
prev = xa_cmpxchg(&fpriv->bo_list_handles, handle, curr, list,
GFP_KERNEL);
if (xa_is_err(prev)) {
r = xa_err(prev);
goto error_put_list;
} else if (prev != curr) {
r = -ENOENT;
goto error_put_list;
}
amdgpu_bo_list_put(curr);
break;
case AMDGPU_BO_LIST_OP_DESTROY:
default:
/* Handled above. */
break;
}
memset(args, 0, sizeof(*args));
args->out.list_handle = handle;
kvfree(info);
return 0;
error_put_list:
amdgpu_bo_list_put(list);
error_free:
kvfree(info);
return r;
}

View File

@@ -43,7 +43,6 @@ struct amdgpu_bo_list_entry {
};
struct amdgpu_bo_list {
struct rcu_head rhead;
struct kref refcount;
struct amdgpu_bo *gds_obj;
struct amdgpu_bo *gws_obj;
@@ -51,24 +50,19 @@ struct amdgpu_bo_list {
unsigned first_userptr;
unsigned num_entries;
/* Protect access during command submission.
*/
struct mutex bo_list_mutex;
struct amdgpu_bo_list_entry entries[] __counted_by(num_entries);
};
int amdgpu_bo_list_get(struct amdgpu_fpriv *fpriv, int id,
struct amdgpu_bo_list **result);
struct amdgpu_bo_list *amdgpu_bo_list_get(struct amdgpu_fpriv *fpriv, u32 id);
void amdgpu_bo_list_put(struct amdgpu_bo_list *list);
int amdgpu_bo_create_list_entry_array(struct drm_amdgpu_bo_list_in *in,
struct drm_amdgpu_bo_list_entry **info_param);
struct drm_amdgpu_bo_list_entry *
amdgpu_bo_create_list_entry_array(struct drm_amdgpu_bo_list_in *in);
int amdgpu_bo_list_create(struct amdgpu_device *adev,
struct drm_file *filp,
struct drm_amdgpu_bo_list_entry *info,
size_t num_entries,
struct amdgpu_bo_list **list);
struct amdgpu_bo_list *
amdgpu_bo_list_create(struct amdgpu_device *adev,
struct drm_file *filp,
struct drm_amdgpu_bo_list_entry *info,
size_t num_entries);
#define amdgpu_bo_list_for_each_entry(e, list) \
for (e = list->entries; \

View File

@@ -289,40 +289,6 @@ struct cper_hdr *amdgpu_cper_alloc_entry(struct amdgpu_device *adev,
return hdr;
}
int amdgpu_cper_generate_ue_record(struct amdgpu_device *adev,
struct aca_bank *bank)
{
struct cper_hdr *fatal = NULL;
struct cper_sec_crashdump_reg_data reg_data = { 0 };
struct amdgpu_ring *ring = &adev->cper.ring_buf;
int ret;
fatal = amdgpu_cper_alloc_entry(adev, AMDGPU_CPER_TYPE_FATAL, 1);
if (!fatal) {
dev_err(adev->dev, "fail to alloc cper entry for ue record\n");
return -ENOMEM;
}
reg_data.status_lo = lower_32_bits(bank->regs[ACA_REG_IDX_STATUS]);
reg_data.status_hi = upper_32_bits(bank->regs[ACA_REG_IDX_STATUS]);
reg_data.addr_lo = lower_32_bits(bank->regs[ACA_REG_IDX_ADDR]);
reg_data.addr_hi = upper_32_bits(bank->regs[ACA_REG_IDX_ADDR]);
reg_data.ipid_lo = lower_32_bits(bank->regs[ACA_REG_IDX_IPID]);
reg_data.ipid_hi = upper_32_bits(bank->regs[ACA_REG_IDX_IPID]);
reg_data.synd_lo = lower_32_bits(bank->regs[ACA_REG_IDX_SYND]);
reg_data.synd_hi = upper_32_bits(bank->regs[ACA_REG_IDX_SYND]);
amdgpu_cper_entry_fill_hdr(adev, fatal, AMDGPU_CPER_TYPE_FATAL, CPER_SEV_FATAL_UNCORRECTED);
ret = amdgpu_cper_entry_fill_fatal_section(adev, fatal, 0, reg_data);
if (ret)
return ret;
amdgpu_cper_ring_write(ring, fatal, fatal->record_length);
kfree(fatal);
return 0;
}
int amdgpu_cper_generate_bp_threshold_record(struct amdgpu_device *adev)
{
struct cper_hdr *bp_threshold = NULL;
@@ -348,83 +314,6 @@ int amdgpu_cper_generate_bp_threshold_record(struct amdgpu_device *adev)
return 0;
}
static enum cper_error_severity amdgpu_aca_err_type_to_cper_sev(struct amdgpu_device *adev,
enum aca_error_type aca_err_type)
{
switch (aca_err_type) {
case ACA_ERROR_TYPE_UE:
return CPER_SEV_FATAL_UNCORRECTED;
case ACA_ERROR_TYPE_CE:
return CPER_SEV_NON_FATAL_CORRECTED;
case ACA_ERROR_TYPE_DEFERRED:
return CPER_SEV_NON_FATAL_UNCORRECTED;
default:
dev_err(adev->dev, "Unknown ACA error type!\n");
return CPER_SEV_FATAL_UNCORRECTED;
}
}
int amdgpu_cper_generate_ce_records(struct amdgpu_device *adev,
struct aca_banks *banks,
uint16_t bank_count)
{
struct cper_hdr *corrected = NULL;
enum cper_error_severity sev = CPER_SEV_NON_FATAL_CORRECTED;
struct amdgpu_ring *ring = &adev->cper.ring_buf;
uint32_t reg_data[CPER_ACA_REG_COUNT] = { 0 };
struct aca_bank_node *node;
struct aca_bank *bank;
uint32_t i = 0;
int ret;
corrected = amdgpu_cper_alloc_entry(adev, AMDGPU_CPER_TYPE_RUNTIME, bank_count);
if (!corrected) {
dev_err(adev->dev, "fail to allocate cper entry for ce records\n");
return -ENOMEM;
}
/* Raise severity if any DE is detected in the ACA bank list */
list_for_each_entry(node, &banks->list, node) {
bank = &node->bank;
if (bank->aca_err_type == ACA_ERROR_TYPE_DEFERRED) {
sev = CPER_SEV_NON_FATAL_UNCORRECTED;
break;
}
}
amdgpu_cper_entry_fill_hdr(adev, corrected, AMDGPU_CPER_TYPE_RUNTIME, sev);
/* Combine CE and DE in cper record */
list_for_each_entry(node, &banks->list, node) {
bank = &node->bank;
reg_data[CPER_ACA_REG_CTL_LO] = lower_32_bits(bank->regs[ACA_REG_IDX_CTL]);
reg_data[CPER_ACA_REG_CTL_HI] = upper_32_bits(bank->regs[ACA_REG_IDX_CTL]);
reg_data[CPER_ACA_REG_STATUS_LO] = lower_32_bits(bank->regs[ACA_REG_IDX_STATUS]);
reg_data[CPER_ACA_REG_STATUS_HI] = upper_32_bits(bank->regs[ACA_REG_IDX_STATUS]);
reg_data[CPER_ACA_REG_ADDR_LO] = lower_32_bits(bank->regs[ACA_REG_IDX_ADDR]);
reg_data[CPER_ACA_REG_ADDR_HI] = upper_32_bits(bank->regs[ACA_REG_IDX_ADDR]);
reg_data[CPER_ACA_REG_MISC0_LO] = lower_32_bits(bank->regs[ACA_REG_IDX_MISC0]);
reg_data[CPER_ACA_REG_MISC0_HI] = upper_32_bits(bank->regs[ACA_REG_IDX_MISC0]);
reg_data[CPER_ACA_REG_CONFIG_LO] = lower_32_bits(bank->regs[ACA_REG_IDX_CONFIG]);
reg_data[CPER_ACA_REG_CONFIG_HI] = upper_32_bits(bank->regs[ACA_REG_IDX_CONFIG]);
reg_data[CPER_ACA_REG_IPID_LO] = lower_32_bits(bank->regs[ACA_REG_IDX_IPID]);
reg_data[CPER_ACA_REG_IPID_HI] = upper_32_bits(bank->regs[ACA_REG_IDX_IPID]);
reg_data[CPER_ACA_REG_SYND_LO] = lower_32_bits(bank->regs[ACA_REG_IDX_SYND]);
reg_data[CPER_ACA_REG_SYND_HI] = upper_32_bits(bank->regs[ACA_REG_IDX_SYND]);
ret = amdgpu_cper_entry_fill_runtime_section(adev, corrected, i++,
amdgpu_aca_err_type_to_cper_sev(adev, bank->aca_err_type),
reg_data, CPER_ACA_REG_COUNT);
if (ret)
return ret;
}
amdgpu_cper_ring_write(ring, corrected, corrected->record_length);
kfree(corrected);
return 0;
}
static bool amdgpu_cper_is_hdr(struct amdgpu_ring *ring, u64 pos)
{
char signature[CPER_SIGNATURE_SZ];
@@ -592,8 +481,7 @@ int amdgpu_cper_init(struct amdgpu_device *adev)
if (amdgpu_sriov_vf(adev) && !amdgpu_sriov_ras_cper_en(adev))
return 0;
else if (!amdgpu_sriov_vf(adev) && !amdgpu_uniras_enabled(adev) &&
!amdgpu_aca_is_enabled(adev))
else if (!amdgpu_sriov_vf(adev) && !amdgpu_uniras_enabled(adev))
return 0;
r = amdgpu_cper_ring_init(adev);
@@ -612,7 +500,7 @@ int amdgpu_cper_init(struct amdgpu_device *adev)
int amdgpu_cper_fini(struct amdgpu_device *adev)
{
if (!amdgpu_aca_is_enabled(adev) && !amdgpu_sriov_ras_cper_en(adev))
if (amdgpu_sriov_vf(adev))
return 0;
adev->cper.enabled = false;

View File

@@ -26,7 +26,6 @@
#define __AMDGPU_CPER_H__
#include "amd_cper.h"
#include "amdgpu_aca.h"
#define CPER_MAX_ALLOWED_COUNT 0x1000
#define CPER_MAX_RING_SIZE 0X100000
@@ -88,13 +87,6 @@ int amdgpu_cper_entry_fill_bad_page_threshold_section(struct amdgpu_device *adev
struct cper_hdr *amdgpu_cper_alloc_entry(struct amdgpu_device *adev,
enum amdgpu_cper_type type,
uint16_t section_count);
/* UE must be encoded into separated cper entries, 1 UE 1 cper */
int amdgpu_cper_generate_ue_record(struct amdgpu_device *adev,
struct aca_bank *bank);
/* CEs and DEs are combined into 1 cper entry */
int amdgpu_cper_generate_ce_records(struct amdgpu_device *adev,
struct aca_banks *banks,
uint16_t bank_count);
/* Bad page threshold is encoded into separated cper entry */
int amdgpu_cper_generate_bp_threshold_record(struct amdgpu_device *adev);
void amdgpu_cper_ring_write(struct amdgpu_ring *ring,

View File

@@ -140,24 +140,19 @@ static int amdgpu_cs_p1_bo_handles(struct amdgpu_cs_parser *p,
struct drm_amdgpu_bo_list_in *data)
{
struct drm_amdgpu_bo_list_entry *info;
int r;
struct amdgpu_bo_list *list;
r = amdgpu_bo_create_list_entry_array(data, &info);
if (r)
return r;
r = amdgpu_bo_list_create(p->adev, p->filp, info, data->bo_number,
&p->bo_list);
if (r)
goto error_free;
info = amdgpu_bo_create_list_entry_array(data);
if (IS_ERR(info))
return PTR_ERR(info);
list = amdgpu_bo_list_create(p->adev, p->filp, info, data->bo_number);
kvfree(info);
if (IS_ERR(list))
return PTR_ERR(list);
p->bo_list = list;
return 0;
error_free:
kvfree(info);
return r;
}
/* Copy the data from userspace and go over it the first time */
@@ -846,6 +841,7 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p,
{
struct amdgpu_fpriv *fpriv = p->filp->driver_priv;
struct ttm_operation_ctx ctx = { true, false };
struct amdgpu_bo_list *list = NULL;
struct amdgpu_vm *vm = &fpriv->vm;
struct amdgpu_bo_list_entry *e;
struct drm_gem_object *obj;
@@ -857,25 +853,24 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p,
if (p->bo_list)
return -EINVAL;
r = amdgpu_bo_list_get(fpriv, cs->in.bo_list_handle,
&p->bo_list);
if (r)
return r;
list = amdgpu_bo_list_get(fpriv, cs->in.bo_list_handle);
} else if (!p->bo_list) {
/* Create a empty bo_list when no handle is provided */
r = amdgpu_bo_list_create(p->adev, p->filp, NULL, 0,
&p->bo_list);
if (r)
return r;
list = amdgpu_bo_list_create(p->adev, p->filp, NULL, 0);
}
mutex_lock(&p->bo_list->bo_list_mutex);
if (IS_ERR(list))
return PTR_ERR(list);
else if (list)
p->bo_list = list;
else
list = p->bo_list;
/* Get userptr backing pages. If pages are updated after registered
* in amdgpu_gem_userptr_ioctl(), amdgpu_cs_list_validate() will do
* amdgpu_ttm_backend_bind() to flush and invalidate new pages
*/
amdgpu_bo_list_for_each_userptr_entry(e, p->bo_list) {
amdgpu_bo_list_for_each_userptr_entry(e, list) {
bool userpage_invalidated = false;
struct amdgpu_bo *bo = e->bo;
@@ -905,7 +900,7 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p,
if (unlikely(r))
goto out_free_user_pages;
amdgpu_bo_list_for_each_entry(e, p->bo_list) {
amdgpu_bo_list_for_each_entry(e, list) {
r = drm_exec_prepare_obj(&p->exec, &e->bo->tbo.base,
TTM_NUM_MOVE_FENCES + p->gang_size);
drm_exec_retry_on_contention(&p->exec);
@@ -924,7 +919,7 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p,
}
}
amdgpu_bo_list_for_each_userptr_entry(e, p->bo_list) {
amdgpu_bo_list_for_each_userptr_entry(e, list) {
struct mm_struct *usermm;
usermm = amdgpu_ttm_tt_get_usermm(e->bo->tbo.ttm);
@@ -977,17 +972,15 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p,
p->bytes_moved_vis);
for (i = 0; i < p->gang_size; ++i)
amdgpu_job_set_resources(p->jobs[i], p->bo_list->gds_obj,
p->bo_list->gws_obj,
p->bo_list->oa_obj);
amdgpu_job_set_resources(p->jobs[i], list->gds_obj,
list->gws_obj, list->oa_obj);
return 0;
out_free_user_pages:
amdgpu_bo_list_for_each_userptr_entry(e, p->bo_list) {
amdgpu_bo_list_for_each_userptr_entry(e, list) {
amdgpu_hmm_range_free(e->range);
e->range = NULL;
}
mutex_unlock(&p->bo_list->bo_list_mutex);
return r;
}
@@ -1371,7 +1364,6 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p,
amdgpu_vm_move_to_lru_tail(p->adev, &fpriv->vm);
mutex_unlock(&p->adev->notifier_lock);
mutex_unlock(&p->bo_list->bo_list_mutex);
return 0;
}
@@ -1443,28 +1435,25 @@ int amdgpu_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
r = amdgpu_cs_patch_jobs(&parser);
if (r)
goto error_backoff;
goto error_fini;
r = amdgpu_cs_vm_handling(&parser);
if (r)
goto error_backoff;
goto error_fini;
r = amdgpu_cs_sync_rings(&parser);
if (r)
goto error_backoff;
goto error_fini;
trace_amdgpu_cs_ibs(&parser);
r = amdgpu_cs_submit(&parser, data);
if (r)
goto error_backoff;
goto error_fini;
amdgpu_cs_parser_fini(&parser);
return 0;
error_backoff:
mutex_unlock(&parser.bo_list->bo_list_mutex);
error_fini:
amdgpu_cs_parser_fini(&parser);
return r;

View File

@@ -283,6 +283,8 @@ static ktime_t amdgpu_ctx_fini_entity(struct amdgpu_device *adev,
if (!entity)
return res;
drm_sched_entity_destroy(&entity->entity);
for (i = 0; i < amdgpu_sched_jobs; ++i) {
res = ktime_add(res, amdgpu_ctx_fence_time(entity->fences[i]));
dma_fence_put(entity->fences[i]);
@@ -294,32 +296,20 @@ static ktime_t amdgpu_ctx_fini_entity(struct amdgpu_device *adev,
return res;
}
static int amdgpu_ctx_get_stable_pstate(struct amdgpu_ctx *ctx,
u32 *stable_pstate)
static u32 amdgpu_get_stable_pstate(struct amdgpu_device *adev)
{
struct amdgpu_device *adev = ctx->mgr->adev;
enum amd_dpm_forced_level current_level;
current_level = amdgpu_dpm_get_performance_level(adev);
switch (current_level) {
switch (amdgpu_dpm_get_performance_level(adev)) {
case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD:
*stable_pstate = AMDGPU_CTX_STABLE_PSTATE_STANDARD;
break;
return AMDGPU_CTX_STABLE_PSTATE_STANDARD;
case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK:
*stable_pstate = AMDGPU_CTX_STABLE_PSTATE_MIN_SCLK;
break;
return AMDGPU_CTX_STABLE_PSTATE_MIN_SCLK;
case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK:
*stable_pstate = AMDGPU_CTX_STABLE_PSTATE_MIN_MCLK;
break;
return AMDGPU_CTX_STABLE_PSTATE_MIN_MCLK;
case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK:
*stable_pstate = AMDGPU_CTX_STABLE_PSTATE_PEAK;
break;
return AMDGPU_CTX_STABLE_PSTATE_PEAK;
default:
*stable_pstate = AMDGPU_CTX_STABLE_PSTATE_NONE;
break;
return AMDGPU_CTX_STABLE_PSTATE_NONE;
}
return 0;
}
static int amdgpu_ctx_init(struct amdgpu_ctx_mgr *mgr, int32_t priority,
@@ -383,9 +373,9 @@ static int __amdgpu_ctx_set_stable_pstate(struct amdgpu_ctx *ctx,
if (current_ctx && current_ctx != ctx)
return -EBUSY;
r = amdgpu_ctx_get_stable_pstate(ctx, &current_stable_pstate);
if (r || current_stable_pstate == stable_pstate)
return r;
current_stable_pstate = amdgpu_get_stable_pstate(adev);
if (current_stable_pstate == stable_pstate)
return 0;
r = amdgpu_dpm_force_performance_level(adev, level);
if (r)
@@ -416,7 +406,7 @@ static int amdgpu_ctx_set_stable_pstate(struct amdgpu_ctx *ctx,
return r;
}
static void amdgpu_ctx_fini(struct kref *ref)
void amdgpu_ctx_fini(struct kref *ref)
{
struct amdgpu_ctx *ctx = container_of(ref, struct amdgpu_ctx, refcount);
struct amdgpu_ctx_mgr *mgr = ctx->mgr;
@@ -504,53 +494,26 @@ static int amdgpu_ctx_alloc(struct amdgpu_device *adev,
if (!ctx)
return -ENOMEM;
mutex_lock(&mgr->lock);
r = idr_alloc(&mgr->ctx_handles, ctx, 1, AMDGPU_VM_MAX_NUM_CTX, GFP_KERNEL);
if (r < 0) {
mutex_unlock(&mgr->lock);
r = amdgpu_ctx_init(mgr, priority, filp, ctx);
if (r) {
kfree(ctx);
return r;
}
*id = (uint32_t)r;
r = amdgpu_ctx_init(mgr, priority, filp, ctx);
if (r) {
idr_remove(&mgr->ctx_handles, *id);
*id = 0;
kfree(ctx);
}
mutex_unlock(&mgr->lock);
r = xa_alloc(&mgr->ctx_handles, id, ctx, xa_limit_32b, GFP_KERNEL);
if (r)
amdgpu_ctx_put(ctx);
return r;
}
static void amdgpu_ctx_do_release(struct kref *ref)
{
struct amdgpu_ctx *ctx;
u32 i, j;
ctx = container_of(ref, struct amdgpu_ctx, refcount);
for (i = 0; i < AMDGPU_HW_IP_NUM; ++i) {
for (j = 0; j < amdgpu_ctx_num_entities[i]; ++j) {
if (!ctx->entities[i][j])
continue;
drm_sched_entity_destroy(&ctx->entities[i][j]->entity);
}
}
amdgpu_ctx_fini(ref);
}
static int amdgpu_ctx_free(struct amdgpu_fpriv *fpriv, uint32_t id)
{
struct amdgpu_ctx_mgr *mgr = &fpriv->ctx_mgr;
struct amdgpu_ctx *ctx;
mutex_lock(&mgr->lock);
ctx = idr_remove(&mgr->ctx_handles, id);
if (ctx)
kref_put(&ctx->refcount, amdgpu_ctx_do_release);
mutex_unlock(&mgr->lock);
ctx = xa_erase(&fpriv->ctx_mgr.ctx_handles, id);
amdgpu_ctx_put(ctx);
return ctx ? 0 : -EINVAL;
}
@@ -559,20 +522,12 @@ static int amdgpu_ctx_query(struct amdgpu_device *adev,
union drm_amdgpu_ctx_out *out)
{
struct amdgpu_ctx *ctx;
struct amdgpu_ctx_mgr *mgr;
unsigned reset_counter;
if (!fpriv)
ctx = amdgpu_ctx_get(fpriv, id);
if (!ctx)
return -EINVAL;
mgr = &fpriv->ctx_mgr;
mutex_lock(&mgr->lock);
ctx = idr_find(&mgr->ctx_handles, id);
if (!ctx) {
mutex_unlock(&mgr->lock);
return -EINVAL;
}
/* TODO: these two are always zero */
out->state.flags = 0x0;
out->state.hangs = 0x0;
@@ -586,7 +541,8 @@ static int amdgpu_ctx_query(struct amdgpu_device *adev,
out->state.reset_status = AMDGPU_CTX_UNKNOWN_RESET;
ctx->reset_counter_query = reset_counter;
mutex_unlock(&mgr->lock);
amdgpu_ctx_put(ctx);
return 0;
}
@@ -619,19 +575,11 @@ static int amdgpu_ctx_query2(struct amdgpu_device *adev,
{
struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
struct amdgpu_ctx *ctx;
struct amdgpu_ctx_mgr *mgr;
if (!fpriv)
ctx = amdgpu_ctx_get(fpriv, id);
if (!ctx)
return -EINVAL;
mgr = &fpriv->ctx_mgr;
mutex_lock(&mgr->lock);
ctx = idr_find(&mgr->ctx_handles, id);
if (!ctx) {
mutex_unlock(&mgr->lock);
return -EINVAL;
}
out->state.flags = 0x0;
out->state.hangs = 0x0;
@@ -671,7 +619,8 @@ static int amdgpu_ctx_query2(struct amdgpu_device *adev,
msecs_to_jiffies(AMDGPU_RAS_COUNTE_DELAY_MS));
}
mutex_unlock(&mgr->lock);
amdgpu_ctx_put(ctx);
return 0;
}
@@ -680,26 +629,26 @@ static int amdgpu_ctx_stable_pstate(struct amdgpu_device *adev,
bool set, u32 *stable_pstate)
{
struct amdgpu_ctx *ctx;
struct amdgpu_ctx_mgr *mgr;
int r;
int r = 0;
if (!fpriv)
ctx = amdgpu_ctx_get(fpriv, id);
if (!ctx)
return -EINVAL;
mgr = &fpriv->ctx_mgr;
mutex_lock(&mgr->lock);
ctx = idr_find(&mgr->ctx_handles, id);
if (!ctx) {
mutex_unlock(&mgr->lock);
return -EINVAL;
}
/*
* The get path is odd in this uapi - it will check whether the context
* id exist, but otherwise does nothing with it. In other words, the
* uapi has historically been implemented as being able to query the
* global device state, as long as the caller supplies a random valid
* context id.
*/
if (set)
r = amdgpu_ctx_set_stable_pstate(ctx, *stable_pstate);
else
r = amdgpu_ctx_get_stable_pstate(ctx, stable_pstate);
*stable_pstate = amdgpu_get_stable_pstate(adev);
mutex_unlock(&mgr->lock);
amdgpu_ctx_put(ctx);
return r;
}
@@ -778,23 +727,14 @@ struct amdgpu_ctx *amdgpu_ctx_get(struct amdgpu_fpriv *fpriv, uint32_t id)
mgr = &fpriv->ctx_mgr;
mutex_lock(&mgr->lock);
ctx = idr_find(&mgr->ctx_handles, id);
xa_lock(&mgr->ctx_handles);
ctx = xa_load(&mgr->ctx_handles, id);
if (ctx)
kref_get(&ctx->refcount);
mutex_unlock(&mgr->lock);
xa_unlock(&mgr->ctx_handles);
return ctx;
}
int amdgpu_ctx_put(struct amdgpu_ctx *ctx)
{
if (ctx == NULL)
return -EINVAL;
kref_put(&ctx->refcount, amdgpu_ctx_do_release);
return 0;
}
uint64_t amdgpu_ctx_add_fence(struct amdgpu_ctx *ctx,
struct drm_sched_entity *entity,
struct dma_fence *fence)
@@ -928,8 +868,7 @@ void amdgpu_ctx_mgr_init(struct amdgpu_ctx_mgr *mgr,
unsigned int i;
mgr->adev = adev;
mutex_init(&mgr->lock);
idr_init_base(&mgr->ctx_handles, 1);
xa_init_flags(&mgr->ctx_handles, XA_FLAGS_ALLOC1);
for (i = 0; i < AMDGPU_HW_IP_NUM; ++i)
atomic64_set(&mgr->time_spend[i], 0);
@@ -938,13 +877,13 @@ void amdgpu_ctx_mgr_init(struct amdgpu_ctx_mgr *mgr,
long amdgpu_ctx_mgr_entity_flush(struct amdgpu_ctx_mgr *mgr, long timeout)
{
struct amdgpu_ctx *ctx;
struct idr *idp;
uint32_t id, i, j;
unsigned long id;
int i, j;
idp = &mgr->ctx_handles;
mutex_lock(&mgr->lock);
idr_for_each_entry(idp, ctx, id) {
xa_lock(&mgr->ctx_handles);
xa_for_each(&mgr->ctx_handles, id, ctx) {
kref_get(&ctx->refcount);
xa_unlock(&mgr->ctx_handles);
for (i = 0; i < AMDGPU_HW_IP_NUM; ++i) {
for (j = 0; j < amdgpu_ctx_num_entities[i]; ++j) {
struct drm_sched_entity *entity;
@@ -956,45 +895,21 @@ long amdgpu_ctx_mgr_entity_flush(struct amdgpu_ctx_mgr *mgr, long timeout)
timeout = drm_sched_entity_flush(entity, timeout);
}
}
amdgpu_ctx_put(ctx);
xa_lock(&mgr->ctx_handles);
}
mutex_unlock(&mgr->lock);
xa_unlock(&mgr->ctx_handles);
return timeout;
}
static void amdgpu_ctx_mgr_entity_fini(struct amdgpu_ctx_mgr *mgr)
{
struct amdgpu_ctx *ctx;
struct idr *idp;
uint32_t id, i, j;
idp = &mgr->ctx_handles;
idr_for_each_entry(idp, ctx, id) {
if (kref_read(&ctx->refcount) != 1) {
drm_err(adev_to_drm(mgr->adev), "ctx %p is still alive\n", ctx);
continue;
}
for (i = 0; i < AMDGPU_HW_IP_NUM; ++i) {
for (j = 0; j < amdgpu_ctx_num_entities[i]; ++j) {
struct drm_sched_entity *entity;
if (!ctx->entities[i][j])
continue;
entity = &ctx->entities[i][j]->entity;
drm_sched_entity_fini(entity);
}
}
kref_put(&ctx->refcount, amdgpu_ctx_fini);
}
}
void amdgpu_ctx_mgr_fini(struct amdgpu_ctx_mgr *mgr)
{
amdgpu_ctx_mgr_entity_fini(mgr);
idr_destroy(&mgr->ctx_handles);
mutex_destroy(&mgr->lock);
struct amdgpu_ctx *ctx;
unsigned long id;
xa_for_each(&mgr->ctx_handles, id, ctx)
amdgpu_ctx_put(ctx);
xa_destroy(&mgr->ctx_handles);
}
void amdgpu_ctx_mgr_usage(struct amdgpu_ctx_mgr *mgr,
@@ -1002,21 +917,21 @@ void amdgpu_ctx_mgr_usage(struct amdgpu_ctx_mgr *mgr,
{
struct amdgpu_ctx *ctx;
unsigned int hw_ip, i;
uint32_t id;
unsigned long id;
/*
* This is a little bit racy because it can be that a ctx or a fence are
* destroyed just in the moment we try to account them. But that is ok
* since exactly that case is explicitely allowed by the interface.
*/
mutex_lock(&mgr->lock);
for (hw_ip = 0; hw_ip < AMDGPU_HW_IP_NUM; ++hw_ip) {
uint64_t ns = atomic64_read(&mgr->time_spend[hw_ip]);
usage[hw_ip] = ns_to_ktime(ns);
}
idr_for_each_entry(&mgr->ctx_handles, ctx, id) {
xa_lock(&mgr->ctx_handles);
xa_for_each(&mgr->ctx_handles, id, ctx) {
for (hw_ip = 0; hw_ip < AMDGPU_HW_IP_NUM; ++hw_ip) {
for (i = 0; i < amdgpu_ctx_num_entities[hw_ip]; ++i) {
struct amdgpu_ctx_entity *centity;
@@ -1030,5 +945,5 @@ void amdgpu_ctx_mgr_usage(struct amdgpu_ctx_mgr *mgr,
}
}
}
mutex_unlock(&mgr->lock);
xa_unlock(&mgr->ctx_handles);
}

View File

@@ -25,6 +25,7 @@
#include <linux/ktime.h>
#include <linux/types.h>
#include <linux/xarray.h>
#include "amdgpu_ring.h"
@@ -60,16 +61,21 @@ struct amdgpu_ctx {
struct amdgpu_ctx_mgr {
struct amdgpu_device *adev;
struct mutex lock;
/* protected by lock */
struct idr ctx_handles;
struct xarray ctx_handles;
atomic64_t time_spend[AMDGPU_HW_IP_NUM];
};
extern const unsigned int amdgpu_ctx_num_entities[AMDGPU_HW_IP_NUM];
struct amdgpu_ctx *amdgpu_ctx_get(struct amdgpu_fpriv *fpriv, uint32_t id);
int amdgpu_ctx_put(struct amdgpu_ctx *ctx);
void amdgpu_ctx_fini(struct kref *kref);
static inline void amdgpu_ctx_put(struct amdgpu_ctx *ctx)
{
if (ctx)
kref_put(&ctx->refcount, amdgpu_ctx_fini);
}
int amdgpu_ctx_get_entity(struct amdgpu_ctx *ctx, u32 hw_ip, u32 instance,
u32 ring, struct drm_sched_entity **entity);

View File

@@ -26,6 +26,7 @@
#include <linux/kthread.h>
#include <linux/pci.h>
#include <linux/uaccess.h>
#include <linux/security.h>
#include <linux/pm_runtime.h>
#include "amdgpu.h"
@@ -1739,6 +1740,12 @@ int amdgpu_debugfs_regs_init(struct amdgpu_device *adev)
struct dentry *ent, *root = minor->debugfs_root;
unsigned int i;
if (security_locked_down(LOCKDOWN_PCI_ACCESS)) {
drm_info(adev_to_drm(adev),
"amdgpu: HW debugfs nodes disabled (kernel lockdown)\n");
return 0;
}
for (i = 0; i < ARRAY_SIZE(debugfs_regs); i++) {
ent = debugfs_create_file(debugfs_regs_names[i],
S_IFREG | 0400, root,

View File

@@ -64,6 +64,7 @@ const char *hw_ip_names[MAX_HWIP] = {
[VCN1_HWIP] = "VCN1",
[VCE_HWIP] = "VCE",
[VPE_HWIP] = "VPE",
[UMSCH_HWIP] = "UMSCH",
[DF_HWIP] = "DF",
[DCE_HWIP] = "DCE",
[OSSSYS_HWIP] = "OSSSYS",

View File

@@ -74,6 +74,7 @@
#include "amdgpu_ras.h"
#include "amdgpu_ras_mgr.h"
#include "amdgpu_pmu.h"
#include "amdgpu_smu.h"
#include "amdgpu_fru_eeprom.h"
#include "amdgpu_reset.h"
#include "amdgpu_virt.h"
@@ -2130,6 +2131,8 @@ static int amdgpu_device_ip_early_init(struct amdgpu_device *adev)
adev->cg_flags &= amdgpu_cg_mask;
adev->pg_flags &= amdgpu_pg_mask;
amdgpu_smu_early_init(adev);
return 0;
}
@@ -3677,6 +3680,10 @@ static void amdgpu_device_sys_interface_fini(struct amdgpu_device *adev)
amdgpu_pm_sysfs_fini(adev);
if (adev->ucode_sysfs_en)
amdgpu_ucode_sysfs_fini(adev);
amdgpu_discovery_sysfs_fini(adev);
amdgpu_preempt_mgr_sysfs_fini(adev);
amdgpu_device_attr_sysfs_fini(adev);
amdgpu_fru_sysfs_fini(adev);
@@ -3773,6 +3780,7 @@ int amdgpu_device_init(struct amdgpu_device *adev,
spin_lock_init(&adev->irq.lock);
amdgpu_early_init_rlc_reg_funcs(adev);
amdgpu_device_init_apu_flags(adev);
r = amdgpu_device_check_arguments(adev);
@@ -4208,6 +4216,7 @@ void amdgpu_device_fini_hw(struct amdgpu_device *adev)
if (adev->mman.initialized)
drain_workqueue(adev->mman.bdev.wq);
adev->shutdown = true;
unregister_pm_notifier(&adev->pm_nb);
@@ -4706,161 +4715,6 @@ int amdgpu_device_resume(struct drm_device *dev, bool notify_clients)
return 0;
}
/**
* amdgpu_device_ip_check_soft_reset - did soft reset succeed
*
* @adev: amdgpu_device pointer
*
* The list of all the hardware IPs that make up the asic is walked and
* the check_soft_reset callbacks are run. check_soft_reset determines
* if the asic is still hung or not.
* Returns true if any of the IPs are still in a hung state, false if not.
*/
static bool amdgpu_device_ip_check_soft_reset(struct amdgpu_device *adev)
{
int i;
bool asic_hang = false;
if (amdgpu_sriov_vf(adev))
return true;
if (amdgpu_asic_need_full_reset(adev))
return true;
for (i = 0; i < adev->num_ip_blocks; i++) {
if (!adev->ip_blocks[i].status.valid)
continue;
if (adev->ip_blocks[i].version->funcs->check_soft_reset)
adev->ip_blocks[i].status.hang =
adev->ip_blocks[i].version->funcs->check_soft_reset(
&adev->ip_blocks[i]);
if (adev->ip_blocks[i].status.hang) {
dev_info(adev->dev, "IP block:%s is hung!\n", adev->ip_blocks[i].version->funcs->name);
asic_hang = true;
}
}
return asic_hang;
}
/**
* amdgpu_device_ip_pre_soft_reset - prepare for soft reset
*
* @adev: amdgpu_device pointer
*
* The list of all the hardware IPs that make up the asic is walked and the
* pre_soft_reset callbacks are run if the block is hung. pre_soft_reset
* handles any IP specific hardware or software state changes that are
* necessary for a soft reset to succeed.
* Returns 0 on success, negative error code on failure.
*/
static int amdgpu_device_ip_pre_soft_reset(struct amdgpu_device *adev)
{
int i, r = 0;
for (i = 0; i < adev->num_ip_blocks; i++) {
if (!adev->ip_blocks[i].status.valid)
continue;
if (adev->ip_blocks[i].status.hang &&
adev->ip_blocks[i].version->funcs->pre_soft_reset) {
r = adev->ip_blocks[i].version->funcs->pre_soft_reset(&adev->ip_blocks[i]);
if (r)
return r;
}
}
return 0;
}
/**
* amdgpu_device_ip_need_full_reset - check if a full asic reset is needed
*
* @adev: amdgpu_device pointer
*
* Some hardware IPs cannot be soft reset. If they are hung, a full gpu
* reset is necessary to recover.
* Returns true if a full asic reset is required, false if not.
*/
static bool amdgpu_device_ip_need_full_reset(struct amdgpu_device *adev)
{
int i;
if (amdgpu_asic_need_full_reset(adev))
return true;
for (i = 0; i < adev->num_ip_blocks; i++) {
if (!adev->ip_blocks[i].status.valid)
continue;
if ((adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GMC) ||
(adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_SMC) ||
(adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_ACP) ||
(adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_DCE) ||
adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_PSP) {
if (adev->ip_blocks[i].status.hang) {
dev_info(adev->dev, "Some block need full reset!\n");
return true;
}
}
}
return false;
}
/**
* amdgpu_device_ip_soft_reset - do a soft reset
*
* @adev: amdgpu_device pointer
*
* The list of all the hardware IPs that make up the asic is walked and the
* soft_reset callbacks are run if the block is hung. soft_reset handles any
* IP specific hardware or software state changes that are necessary to soft
* reset the IP.
* Returns 0 on success, negative error code on failure.
*/
static int amdgpu_device_ip_soft_reset(struct amdgpu_device *adev)
{
int i, r = 0;
for (i = 0; i < adev->num_ip_blocks; i++) {
if (!adev->ip_blocks[i].status.valid)
continue;
if (adev->ip_blocks[i].status.hang &&
adev->ip_blocks[i].version->funcs->soft_reset) {
r = adev->ip_blocks[i].version->funcs->soft_reset(&adev->ip_blocks[i]);
if (r)
return r;
}
}
return 0;
}
/**
* amdgpu_device_ip_post_soft_reset - clean up from soft reset
*
* @adev: amdgpu_device pointer
*
* The list of all the hardware IPs that make up the asic is walked and the
* post_soft_reset callbacks are run if the asic was hung. post_soft_reset
* handles any IP specific hardware or software state changes that are
* necessary after the IP has been soft reset.
* Returns 0 on success, negative error code on failure.
*/
static int amdgpu_device_ip_post_soft_reset(struct amdgpu_device *adev)
{
int i, r = 0;
for (i = 0; i < adev->num_ip_blocks; i++) {
if (!adev->ip_blocks[i].status.valid)
continue;
if (adev->ip_blocks[i].status.hang &&
adev->ip_blocks[i].version->funcs->post_soft_reset)
r = adev->ip_blocks[i].version->funcs->post_soft_reset(&adev->ip_blocks[i]);
if (r)
return r;
}
return 0;
}
/**
* amdgpu_device_reset_sriov - reset ASIC for SR-IOV vf
*
@@ -5152,20 +5006,7 @@ int amdgpu_device_pre_asic_reset(struct amdgpu_device *adev,
/* Don't suspend on bare metal if we are not going to HW reset the ASIC */
if (!amdgpu_sriov_vf(adev)) {
if (!need_full_reset)
need_full_reset = amdgpu_device_ip_need_full_reset(adev);
if (!need_full_reset && amdgpu_gpu_recovery &&
amdgpu_device_ip_check_soft_reset(adev)) {
amdgpu_device_ip_pre_soft_reset(adev);
r = amdgpu_device_ip_soft_reset(adev);
amdgpu_device_ip_post_soft_reset(adev);
if (r || amdgpu_device_ip_check_soft_reset(adev)) {
dev_info(adev->dev, "soft reset failed, will fallback to full reset!\n");
need_full_reset = true;
}
}
need_full_reset = true;
if (!test_bit(AMDGPU_SKIP_COREDUMP, &reset_context->flags)) {
dev_info(tmp_adev->dev, "Dumping IP State\n");
@@ -5618,8 +5459,7 @@ static void amdgpu_device_halt_activities(struct amdgpu_device *adev,
drm_client_dev_suspend(adev_to_drm(tmp_adev));
/* disable ras on ALL IPs */
if (!need_emergency_restart && !amdgpu_reset_in_dpc(adev) &&
amdgpu_device_ip_need_full_reset(tmp_adev))
if (!need_emergency_restart && !amdgpu_reset_in_dpc(adev))
amdgpu_ras_suspend(tmp_adev);
amdgpu_userq_pre_reset(tmp_adev);
@@ -6891,7 +6731,7 @@ ssize_t amdgpu_get_soft_full_reset_mask(struct amdgpu_ring *ring)
if (unlikely(!ring->adev->debug_disable_soft_recovery) &&
!amdgpu_sriov_vf(ring->adev) && ring->funcs->soft_recovery)
size |= AMDGPU_RESET_TYPE_SOFT_RESET;
size |= AMDGPU_RESET_TYPE_SOFT_RECOVERY;
return size;
}
@@ -6907,8 +6747,8 @@ ssize_t amdgpu_show_reset_mask(char *buf, uint32_t supported_reset)
}
if (supported_reset & AMDGPU_RESET_TYPE_SOFT_RESET)
size += sysfs_emit_at(buf, size, "soft ");
if (supported_reset & AMDGPU_RESET_TYPE_SOFT_RECOVERY)
size += sysfs_emit_at(buf, size, "soft_recovery ");
if (supported_reset & AMDGPU_RESET_TYPE_PER_QUEUE)
size += sysfs_emit_at(buf, size, "queue ");

View File

@@ -22,6 +22,7 @@
*/
#include <linux/firmware.h>
#include <linux/kernfs.h>
#include "amdgpu.h"
#include "amdgpu_discovery.h"
@@ -148,6 +149,26 @@ MODULE_FIRMWARE("amdgpu/aldebaran_ip_discovery.bin");
#define mmDRIVER_SCRATCH_1 0x95
#define mmDRIVER_SCRATCH_2 0x96
struct ip_discovery_top {
struct kobject kobj;
struct kset die_kset;
struct pci_dev *pdev;
struct amdgpu_device *adev;
uint8_t *discovery_bin;
uint32_t bin_size;
bool standalone_mode;
};
/* List to track early-initialized ip_discovery_top entries */
struct early_ip_discovery {
struct list_head list;
struct pci_dev *pdev;
struct ip_discovery_top *ip_top;
};
static LIST_HEAD(early_ip_discovery_list);
static DEFINE_MUTEX(early_ip_discovery_mutex);
static const char *hw_id_names[HW_ID_MAX] = {
[MP1_HWID] = "MP1",
[MP2_HWID] = "MP2",
@@ -226,6 +247,7 @@ static const char *hw_id_names[HW_ID_MAX] = {
[XGBE_HWID] = "XGBE",
[MP0_HWID] = "MP0",
[VPE_HWID] = "VPE",
[UMSCH_HWID] = "UMSCH",
[ATU_HWID] = "ATU",
[AIGC_HWID] = "AIGC",
};
@@ -258,6 +280,7 @@ static int hw_id_map[MAX_HWIP] = {
[DCI_HWIP] = DCI_HWID,
[PCIE_HWIP] = PCIE_HWID,
[VPE_HWIP] = VPE_HWID,
[UMSCH_HWIP] = UMSCH_HWID,
[ISP_HWIP] = ISP_HWID,
[ATU_HWIP] = ATU_HWID,
};
@@ -542,25 +565,37 @@ static const char *amdgpu_discovery_get_fw_name(struct amdgpu_device *adev)
}
}
static struct table_info *
amdgpu_discovery_get_table_info_from_bin(uint8_t *discovery_bin,
uint16_t table_id)
{
struct binary_header *bhdr = (struct binary_header *)discovery_bin;
struct binary_header_v2 *bhdrv2;
switch (bhdr->version_major) {
case 2:
bhdrv2 = (struct binary_header_v2 *)discovery_bin;
return &bhdrv2->table_list[table_id];
case 1:
case 0:
return &bhdr->table_list[table_id];
default:
return NULL;
}
}
static int amdgpu_discovery_get_table_info(struct amdgpu_device *adev,
struct table_info **info,
uint16_t table_id)
{
struct binary_header *bhdr =
(struct binary_header *)adev->discovery.bin;
struct binary_header_v2 *bhdrv2;
switch (bhdr->version_major) {
case 2:
bhdrv2 = (struct binary_header_v2 *)adev->discovery.bin;
*info = &bhdrv2->table_list[table_id];
break;
case 1:
case 0:
*info = &bhdr->table_list[table_id];
break;
default:
dev_err(adev->dev, "Invalid ip discovery table version %d\n",bhdr->version_major);
*info = amdgpu_discovery_get_table_info_from_bin(adev->discovery.bin,
table_id);
if (!*info) {
dev_err(adev->dev, "Invalid ip discovery table version %d\n",
bhdr->version_major);
return -EINVAL;
}
@@ -724,11 +759,11 @@ static int amdgpu_discovery_init(struct amdgpu_device *adev)
return r;
}
static void amdgpu_discovery_sysfs_fini(struct amdgpu_device *adev);
void amdgpu_discovery_fini(struct amdgpu_device *adev)
{
amdgpu_discovery_sysfs_fini(adev);
if (adev->discovery.ip_top && !adev->discovery.ip_top->standalone_mode)
amdgpu_discovery_sysfs_fini(adev);
kfree(adev->discovery.bin);
adev->discovery.bin = NULL;
}
@@ -737,15 +772,17 @@ static int amdgpu_discovery_validate_ip(struct amdgpu_device *adev,
uint8_t instance, uint16_t hw_id)
{
if (instance >= HWIP_MAX_INSTANCE) {
dev_err(adev->dev,
"Unexpected instance_number (%d) from ip discovery blob\n",
instance);
if (adev)
dev_err(adev->dev,
"Unexpected instance_number (%d) from ip discovery blob\n",
instance);
return -EINVAL;
}
if (hw_id >= HW_ID_MAX) {
dev_err(adev->dev,
"Unexpected hw_id (%d) from ip discovery blob\n",
hw_id);
if (adev)
dev_err(adev->dev,
"Unexpected hw_id (%d) from ip discovery blob\n",
hw_id);
return -EINVAL;
}
@@ -1111,12 +1148,6 @@ static const struct kobj_type ip_discovery_ktype = {
.sysfs_ops = &kobj_sysfs_ops,
};
struct ip_discovery_top {
struct kobject kobj; /* ip_discovery/ */
struct kset die_kset; /* ip_discovery/die/, contains ip_die_entry */
struct amdgpu_device *adev;
};
static void die_kobj_release(struct kobject *kobj)
{
struct ip_discovery_top *ip_top = container_of(to_kset(kobj),
@@ -1132,8 +1163,14 @@ static void ip_disc_release(struct kobject *kobj)
kobj);
struct amdgpu_device *adev = ip_top->adev;
/* In standalone mode, discovery_bin is managed by devm and will be
* freed automatically when the PCI device is removed. Do not manually
* free it here to avoid double-free.
*/
kfree(ip_top);
adev->discovery.ip_top = NULL;
if (adev)
adev->discovery.ip_top = NULL;
}
static uint8_t amdgpu_discovery_get_harvest_info(struct amdgpu_device *adev,
@@ -1141,6 +1178,10 @@ static uint8_t amdgpu_discovery_get_harvest_info(struct amdgpu_device *adev,
{
uint8_t harvest = 0;
/* In early init mode (adev == NULL), harvest info is not available */
if (!adev)
return 0;
/* Until a uniform way is figured, get mask based on hwid */
switch (hw_id) {
case VCN_HWID:
@@ -1169,11 +1210,14 @@ static uint8_t amdgpu_discovery_get_harvest_info(struct amdgpu_device *adev,
}
static int amdgpu_discovery_sysfs_ips(struct amdgpu_device *adev,
struct ip_discovery_top *ip_top,
struct ip_die_entry *ip_die_entry,
const size_t _ip_offset, const int num_ips,
bool reg_base_64)
{
uint8_t *discovery_bin = adev->discovery.bin;
uint8_t *discovery_bin = ip_top->standalone_mode ?
ip_top->discovery_bin :
adev->discovery.bin;
int ii, jj, kk, res;
uint16_t hw_id;
uint8_t inst;
@@ -1270,10 +1314,12 @@ static int amdgpu_discovery_sysfs_ips(struct amdgpu_device *adev,
return 0;
}
static int amdgpu_discovery_sysfs_recurse(struct amdgpu_device *adev)
static int amdgpu_discovery_sysfs_recurse(struct amdgpu_device *adev,
struct ip_discovery_top *ip_top)
{
struct ip_discovery_top *ip_top = adev->discovery.ip_top;
uint8_t *discovery_bin = adev->discovery.bin;
uint8_t *discovery_bin = ip_top->standalone_mode ?
ip_top->discovery_bin :
adev->discovery.bin;
struct table_info *info;
struct ip_discovery_header *ihdr;
struct die_header *dhdr;
@@ -1282,9 +1328,10 @@ static int amdgpu_discovery_sysfs_recurse(struct amdgpu_device *adev)
size_t ip_offset;
int ii, res;
res = amdgpu_discovery_get_table_info(adev, &info, IP_DISCOVERY);
if (res)
return res;
info = amdgpu_discovery_get_table_info_from_bin(discovery_bin,
IP_DISCOVERY);
if (!info)
return -EINVAL;
ihdr = (struct ip_discovery_header
*)(discovery_bin +
le16_to_cpu(info->offset));
@@ -1322,7 +1369,8 @@ static int amdgpu_discovery_sysfs_recurse(struct amdgpu_device *adev)
return res;
}
amdgpu_discovery_sysfs_ips(adev, ip_die_entry, ip_offset, num_ips, !!ihdr->base_addr_64_bit);
amdgpu_discovery_sysfs_ips(adev, ip_top, ip_die_entry, ip_offset,
num_ips, !!ihdr->base_addr_64_bit);
}
return 0;
@@ -1338,12 +1386,30 @@ static int amdgpu_discovery_sysfs_init(struct amdgpu_device *adev)
if (!discovery_bin)
return -EINVAL;
/* If early init already created sysfs in standalone mode, skip normal init */
if (adev->discovery.ip_top && adev->discovery.ip_top->standalone_mode)
return 0;
ip_top = kzalloc_obj(*ip_top);
if (!ip_top)
return -ENOMEM;
ip_top->adev = adev;
adev->discovery.ip_top = ip_top;
/* Check if ip_discovery already exists before creating.
* This shouldn't normally happen but handle it gracefully.
*/
if (adev->dev->kobj.sd) {
struct kernfs_node *existing;
existing = kernfs_find_and_get(adev->dev->kobj.sd, "ip_discovery");
if (existing) {
kernfs_put(existing);
kfree(ip_top);
return 0;
}
}
res = kobject_init_and_add(&ip_top->kobj, &ip_discovery_ktype,
&adev->dev->kobj, "ip_discovery");
if (res) {
@@ -1351,6 +1417,8 @@ static int amdgpu_discovery_sysfs_init(struct amdgpu_device *adev)
goto Err;
}
adev->discovery.ip_top = ip_top;
die_kset = &ip_top->die_kset;
kobject_set_name(&die_kset->kobj, "%s", "die");
die_kset->kobj.parent = &ip_top->kobj;
@@ -1365,7 +1433,7 @@ static int amdgpu_discovery_sysfs_init(struct amdgpu_device *adev)
ip_hw_instance_attrs[ii] = &ip_hw_attr[ii].attr;
ip_hw_instance_attrs[ii] = NULL;
res = amdgpu_discovery_sysfs_recurse(adev);
res = amdgpu_discovery_sysfs_recurse(adev, ip_top);
return res;
Err:
@@ -1412,7 +1480,7 @@ static void amdgpu_discovery_sysfs_die_free(struct ip_die_entry *ip_die_entry)
kobject_put(&ip_die_entry->ip_kset.kobj);
}
static void amdgpu_discovery_sysfs_fini(struct amdgpu_device *adev)
void amdgpu_discovery_sysfs_fini(struct amdgpu_device *adev)
{
struct ip_discovery_top *ip_top = adev->discovery.ip_top;
struct list_head *el, *tmp;
@@ -1421,6 +1489,16 @@ static void amdgpu_discovery_sysfs_fini(struct amdgpu_device *adev)
if (!ip_top)
return;
/*
* In standalone mode the sysfs hierarchy is tied to the PCI device
* lifetime and is torn down by amdgpu_discovery_sysfs_early_fini().
* Freeing it here would leave a dangling pointer in the early
* discovery list, causing a use-after-free on driver unbind.
*/
if (ip_top->standalone_mode)
return;
adev->discovery.ip_top = NULL;
die_kset = &ip_top->die_kset;
spin_lock(&die_kset->list_lock);
list_for_each_prev_safe(el, tmp, &die_kset->list) {
@@ -1479,6 +1557,150 @@ void amdgpu_discovery_dump(struct amdgpu_device *adev, struct drm_printer *p)
spin_unlock(&die_kset->list_lock);
}
int amdgpu_discovery_sysfs_early_init(struct amdgpu_device *adev, struct pci_dev *pdev)
{
struct ip_discovery_top *ip_top;
struct early_ip_discovery *early_entry, *tmp;
struct kset *die_kset;
uint8_t *discovery_bin;
int res, ii;
if (!adev || !adev->discovery.bin)
return -EINVAL;
if (adev->discovery.ip_top)
return 0;
mutex_lock(&early_ip_discovery_mutex);
list_for_each_entry_safe(early_entry, tmp, &early_ip_discovery_list, list) {
if (early_entry->pdev == pdev) {
adev->discovery.ip_top = early_entry->ip_top;
early_entry->ip_top->adev = adev;
mutex_unlock(&early_ip_discovery_mutex);
return 0;
}
}
mutex_unlock(&early_ip_discovery_mutex);
discovery_bin = adev->discovery.bin;
early_entry = kzalloc(sizeof(*early_entry), GFP_KERNEL);
if (!early_entry)
return -ENOMEM;
ip_top = kzalloc(sizeof(*ip_top), GFP_KERNEL);
if (!ip_top) {
kfree(early_entry);
return -ENOMEM;
}
ip_top->discovery_bin = devm_kmemdup(&pdev->dev, discovery_bin,
DISCOVERY_TMR_SIZE, GFP_KERNEL);
if (!ip_top->discovery_bin) {
kfree(ip_top);
kfree(early_entry);
return -ENOMEM;
}
ip_top->bin_size = DISCOVERY_TMR_SIZE;
ip_top->pdev = pdev;
ip_top->adev = adev;
ip_top->standalone_mode = true;
/* Check if ip_discovery already exists (from previous probe attempt).
* This can happen if the module was unloaded and reloaded but the
* sysfs persisted (tied to PCI device lifetime).
*/
if (pdev->dev.kobj.sd) {
struct kernfs_node *existing;
existing = kernfs_find_and_get(pdev->dev.kobj.sd, "ip_discovery");
if (existing) {
kernfs_put(existing);
kfree(ip_top);
kfree(early_entry);
return 0;
}
}
res = kobject_init_and_add(&ip_top->kobj, &ip_discovery_ktype,
&pdev->dev.kobj, "ip_discovery");
if (res)
goto err_put_kobj;
adev->discovery.ip_top = ip_top;
die_kset = &ip_top->die_kset;
kobject_set_name(&die_kset->kobj, "%s", "die");
die_kset->kobj.parent = &ip_top->kobj;
die_kset->kobj.ktype = &die_kobj_ktype;
res = kset_register(&ip_top->die_kset);
if (res)
goto err_put_die_kset;
for (ii = 0; ii < ARRAY_SIZE(ip_hw_attr); ii++)
ip_hw_instance_attrs[ii] = &ip_hw_attr[ii].attr;
ip_hw_instance_attrs[ii] = NULL;
res = amdgpu_discovery_sysfs_recurse(NULL, ip_top);
if (res)
goto err_put_die_kset;
early_entry->pdev = pdev;
early_entry->ip_top = ip_top;
mutex_lock(&early_ip_discovery_mutex);
list_add(&early_entry->list, &early_ip_discovery_list);
mutex_unlock(&early_ip_discovery_mutex);
return 0;
err_put_die_kset:
kobject_put(&ip_top->die_kset.kobj);
err_put_kobj:
kobject_put(&ip_top->kobj);
kfree(early_entry);
adev->discovery.ip_top = NULL;
return res;
}
void amdgpu_discovery_sysfs_early_fini(struct pci_dev *pdev)
{
struct early_ip_discovery *entry, *tmp_entry;
struct ip_discovery_top *ip_top = NULL;
struct list_head *el, *tmp;
struct kset *die_kset;
/* Find the entry in our tracking list */
mutex_lock(&early_ip_discovery_mutex);
list_for_each_entry_safe(entry, tmp_entry, &early_ip_discovery_list, list) {
if (entry->pdev == pdev) {
ip_top = entry->ip_top;
list_del(&entry->list);
kfree(entry);
break;
}
}
mutex_unlock(&early_ip_discovery_mutex);
if (!ip_top)
return;
/* Clean up sysfs hierarchy */
die_kset = &ip_top->die_kset;
spin_lock(&die_kset->list_lock);
list_for_each_prev_safe(el, tmp, &die_kset->list) {
list_del_init(el);
spin_unlock(&die_kset->list_lock);
amdgpu_discovery_sysfs_die_free(to_ip_die_entry(list_to_kobj(el)));
spin_lock(&die_kset->list_lock);
}
spin_unlock(&die_kset->list_lock);
kobject_put(&ip_top->die_kset.kobj);
kobject_put(&ip_top->kobj);
/* ip_top itself will be freed by kobject_put via ip_disc_release */
}
/* ================================================== */
@@ -1504,6 +1726,9 @@ static int amdgpu_discovery_reg_base_init(struct amdgpu_device *adev)
r = amdgpu_discovery_init(adev);
if (r)
return r;
amdgpu_discovery_sysfs_early_init(adev, adev->pdev);
discovery_bin = adev->discovery.bin;
wafl_ver = 0;
adev->gfx.xcc_mask = 0;
@@ -2636,7 +2861,12 @@ static int amdgpu_discovery_set_mm_ip_blocks(struct amdgpu_device *adev)
return -EINVAL;
}
} else {
switch (amdgpu_ip_version(adev, UVD_HWIP, 0)) {
uint32_t vcn_version = amdgpu_ip_version(adev, UVD_HWIP, 0);
/* no VCN discovered; nothing to add */
if (!vcn_version)
return 0;
switch (vcn_version) {
case IP_VERSION(1, 0, 0):
case IP_VERSION(1, 0, 1):
amdgpu_device_ip_block_add(adev, &vcn_v1_0_ip_block);
@@ -2704,7 +2934,7 @@ static int amdgpu_discovery_set_mm_ip_blocks(struct amdgpu_device *adev)
default:
dev_err(adev->dev,
"Failed to add vcn/jpeg ip block(UVD_HWIP:0x%x)\n",
amdgpu_ip_version(adev, UVD_HWIP, 0));
vcn_version);
return -EINVAL;
}
}

View File

@@ -41,6 +41,7 @@ struct amdgpu_discovery_info {
bool reserve_tmr;
};
void amdgpu_discovery_sysfs_fini(struct amdgpu_device *adev);
void amdgpu_discovery_fini(struct amdgpu_device *adev);
int amdgpu_discovery_set_ip_blocks(struct amdgpu_device *adev);
@@ -53,4 +54,9 @@ int amdgpu_discovery_get_gc_major_minor_version(struct amdgpu_device *adev,
void amdgpu_discovery_dump(struct amdgpu_device *adev, struct drm_printer *p);
/* Early sysfs functions for persistent ip_discovery export */
int amdgpu_discovery_sysfs_early_init(struct amdgpu_device *adev,
struct pci_dev *pdev);
void amdgpu_discovery_sysfs_early_fini(struct pci_dev *pdev);
#endif /* __AMDGPU_DISCOVERY__ */

View File

@@ -33,7 +33,6 @@
#include <drm/drm_vblank.h>
#include <linux/cc_platform.h>
#include <linux/console.h>
#include <linux/dynamic_debug.h>
#include <linux/module.h>
#include <linux/mmu_notifier.h>
@@ -146,7 +145,9 @@ enum AMDGPU_DEBUG_MASK {
AMDGPU_DEBUG_SMU_POOL = BIT(7),
AMDGPU_DEBUG_VM_USERPTR = BIT(8),
AMDGPU_DEBUG_DISABLE_RAS_CE_LOG = BIT(9),
AMDGPU_DEBUG_ENABLE_CE_CS = BIT(10)
AMDGPU_DEBUG_ENABLE_CE_CS = BIT(10),
AMDGPU_DEBUG_HIBERNATION_THAW_RESUME_GPU = BIT(11),
AMDGPU_DEBUG_DISABLE_IP_BLOCK_SOFT_RESET = BIT(12),
};
unsigned int amdgpu_vram_limit = UINT_MAX;
@@ -1939,6 +1940,7 @@ static const struct pci_device_id pciidlist[] = {
{0x1002, 0x6646, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|AMD_IS_MOBILITY},
{0x1002, 0x6647, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|AMD_IS_MOBILITY},
{0x1002, 0x6649, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE},
{0x1002, 0x664D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE},
{0x1002, 0x6650, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE},
{0x1002, 0x6651, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE},
{0x1002, 0x6658, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE},
@@ -2008,6 +2010,7 @@ static const struct pci_device_id pciidlist[] = {
{0x1002, 0x6930, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TONGA},
{0x1002, 0x6938, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TONGA},
{0x1002, 0x6939, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TONGA},
{0x1002, 0x693B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TONGA},
/* fiji */
{0x1002, 0x7300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_FIJI},
{0x1002, 0x730F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_FIJI},
@@ -2036,6 +2039,7 @@ static const struct pci_device_id pciidlist[] = {
{0x1002, 0x67C4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS10},
{0x1002, 0x67C7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS10},
{0x1002, 0x67D0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS10},
{0x1002, 0x67D4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS10},
{0x1002, 0x67DF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS10},
{0x1002, 0x67C8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS10},
{0x1002, 0x67C9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS10},
@@ -2049,6 +2053,7 @@ static const struct pci_device_id pciidlist[] = {
{0x1002, 0x6985, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12},
{0x1002, 0x6986, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12},
{0x1002, 0x6987, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12},
{0x1002, 0x698F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12},
{0x1002, 0x6995, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12},
{0x1002, 0x6997, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12},
{0x1002, 0x699F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12},
@@ -2250,7 +2255,7 @@ static void amdgpu_init_debug_options(struct amdgpu_device *adev)
}
if (amdgpu_debug_mask & AMDGPU_DEBUG_DISABLE_GPU_SOFT_RECOVERY) {
pr_info("debug: soft reset for GPU recovery disabled\n");
pr_info("debug: soft recovery disabled\n");
adev->debug_disable_soft_recovery = true;
}
@@ -2291,6 +2296,16 @@ static void amdgpu_init_debug_options(struct amdgpu_device *adev)
pr_info("debug: allowing command submission to CE engine\n");
adev->debug_enable_ce_cs = true;
}
if (amdgpu_debug_mask & AMDGPU_DEBUG_HIBERNATION_THAW_RESUME_GPU) {
pr_info("debug: resume gpu in thaw() of hibernation\n");
adev->debug_hibernation_thaw_resume_gpu = true;
}
if (amdgpu_debug_mask & AMDGPU_DEBUG_DISABLE_IP_BLOCK_SOFT_RESET) {
pr_info("debug: IP block soft reset disabled\n");
adev->debug_disable_ip_block_soft_reset = true;
}
}
static unsigned long amdgpu_fix_asic_type(struct pci_dev *pdev, unsigned long flags)
@@ -2552,6 +2567,8 @@ amdgpu_pci_remove(struct pci_dev *pdev)
amdgpu_driver_unload_kms(dev);
amdgpu_discovery_sysfs_early_fini(pdev);
/*
* Flush any in flight DMA operations from device.
* Clear the Bus Master Enable bit and then wait on the PCIe Device
@@ -2705,9 +2722,10 @@ static int amdgpu_pmops_freeze(struct device *dev)
static int amdgpu_pmops_thaw(struct device *dev)
{
struct drm_device *drm_dev = dev_get_drvdata(dev);
struct amdgpu_device *adev = drm_to_adev(drm_dev);
/* do not resume device if it's normal hibernation */
if (console_suspend_enabled &&
if (!adev->debug_hibernation_thaw_resume_gpu &&
!pm_hibernate_is_recovering() &&
!pm_hibernation_mode_is_suspend())
return 0;
@@ -3076,6 +3094,7 @@ const struct drm_ioctl_desc amdgpu_ioctls_kms[] = {
DRM_IOCTL_DEF_DRV(AMDGPU_USERQ_SIGNAL, amdgpu_userq_signal_ioctl, DRM_AUTH|DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(AMDGPU_USERQ_WAIT, amdgpu_userq_wait_ioctl, DRM_AUTH|DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(AMDGPU_GEM_LIST_HANDLES, amdgpu_gem_list_handles_ioctl, DRM_AUTH|DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(AMDGPU_PROC_OPTIONS, amdgpu_proc_options_ioctl, DRM_AUTH|DRM_RENDER_ALLOW),
};
static const struct drm_driver amdgpu_kms_driver = {

View File

@@ -727,6 +727,15 @@ void amdgpu_ring_set_fence_errors_and_reemit(struct amdgpu_ring *ring,
last_seq = amdgpu_fence_read(ring) & ring->fence_drv.num_fences_mask;
seq = ring->fence_drv.sync_seq & ring->fence_drv.num_fences_mask;
/* If there is nothing to reemit, return early and set an error on the fence
* if applicable. If all of the fences are siganlled, this will be a nop.
* if there are still fences and ring_backup_entries_to_copy is 0, then
* we are skipping it on purpose.
*/
if (!ring->ring_backup_entries_to_copy) {
amdgpu_fence_driver_force_completion(ring, &guilty_fence->base);
return;
}
ring->reemit = true;
amdgpu_ring_alloc(ring, ring->ring_backup_entries_to_copy);
spin_lock_irqsave(&ring->fence_drv.lock, flags);
@@ -741,7 +750,8 @@ void amdgpu_ring_set_fence_errors_and_reemit(struct amdgpu_ring *ring,
if (unprocessed && !dma_fence_is_signaled_locked(unprocessed)) {
fence = container_of(unprocessed, struct amdgpu_fence, base);
is_guilty_fence = fence == guilty_fence;
is_guilty_context = fence->context == guilty_fence->context;
is_guilty_context = guilty_fence ?
(fence->context == guilty_fence->context) : false;
/* mark all fences from the guilty context with an error */
if (is_guilty_fence)
@@ -794,6 +804,17 @@ void amdgpu_ring_backup_unprocessed_commands(struct amdgpu_ring *ring,
seq = ring->fence_drv.sync_seq & ring->fence_drv.num_fences_mask;
ring->ring_backup_entries_to_copy = 0;
/* if we've already seen this fence, return early.
* ring->ring_backup_entries_to_copy is set to 0 so
* the reemit helper will return early as well to
* avoid getting stuck in a reemit loop.
*/
if (ring->guilty_fence == guilty_fence) {
ring->guilty_fence = NULL;
return;
}
ring->guilty_fence = guilty_fence;
do {
last_seq++;
last_seq &= ring->fence_drv.num_fences_mask;
@@ -811,6 +832,36 @@ void amdgpu_ring_backup_unprocessed_commands(struct amdgpu_ring *ring,
} while (last_seq != seq);
}
struct amdgpu_fence *
amdgpu_ring_find_guilty_fence(struct amdgpu_ring *ring)
{
struct dma_fence *unprocessed;
struct dma_fence __rcu **ptr;
struct amdgpu_fence *fence;
u32 seq, last_seq;
last_seq = amdgpu_fence_read(ring) & ring->fence_drv.num_fences_mask;
seq = ring->fence_drv.sync_seq & ring->fence_drv.num_fences_mask;
do {
last_seq++;
last_seq &= ring->fence_drv.num_fences_mask;
ptr = &ring->fence_drv.fences[last_seq];
rcu_read_lock();
unprocessed = rcu_dereference(*ptr);
if (unprocessed && !dma_fence_is_signaled(unprocessed)) {
fence = container_of(unprocessed, struct amdgpu_fence, base);
rcu_read_unlock();
return fence;
}
rcu_read_unlock();
} while (last_seq != seq);
return NULL;
}
/*
* Common fence implementation
*/

View File

@@ -34,6 +34,7 @@
#include "amdgpu_xcp.h"
#include "amdgpu_xgmi.h"
#include "amdgpu_mes.h"
#include "mes_userqueue.h"
#include "nvd.h"
/* delay 0.1 second to enable gfx off feature */
@@ -377,6 +378,30 @@ int amdgpu_gfx_kiq_init(struct amdgpu_device *adev,
return 0;
}
static void amdgpu_gfx_mqd_reset_restore(struct amdgpu_ring *ring)
{
struct amdgpu_device *adev = ring->adev;
int mqd_idx, mqd_size;
/* restore mqd with the backup copy */
if (ring->funcs->type == AMDGPU_RING_TYPE_COMPUTE) {
mqd_idx = ring - &adev->gfx.compute_ring[0];
mqd_size = adev->mqds[AMDGPU_HW_IP_COMPUTE].mqd_size;
if (adev->gfx.mec.mqd_backup[mqd_idx])
memcpy_toio(ring->mqd_ptr, adev->gfx.mec.mqd_backup[mqd_idx], mqd_size);
} else if (ring->funcs->type == AMDGPU_RING_TYPE_GFX) {
mqd_size = adev->mqds[AMDGPU_HW_IP_GFX].mqd_size;
mqd_idx = ring - &adev->gfx.gfx_ring[0];
if (adev->gfx.me.mqd_backup[mqd_idx])
memcpy_toio(ring->mqd_ptr, adev->gfx.me.mqd_backup[mqd_idx], mqd_size);
}
/* reset the ring */
ring->wptr = 0;
atomic64_set((atomic64_t *)ring->wptr_cpu_addr, 0);
amdgpu_ring_clear_ring(ring);
}
/* create MQD for each compute/gfx queue */
int amdgpu_gfx_mqd_sw_init(struct amdgpu_device *adev,
unsigned int mqd_size, int xcc_id)
@@ -1964,6 +1989,60 @@ static ssize_t amdgpu_gfx_get_compute_reset_mask(struct device *dev,
return amdgpu_show_reset_mask(buf, adev->gfx.compute_supported_reset);
}
static int amdgpu_gfx_mes_reset_queue_start(struct amdgpu_ring *ring,
unsigned int vmid,
struct amdgpu_fence *timedout_fence,
bool use_mmio)
{
struct amdgpu_device *adev = ring->adev;
bool reinit_queue;
int r;
if ((ring->funcs->type == AMDGPU_RING_TYPE_COMPUTE) &&
adev->mes.compute_pipe_reset_enabled)
reinit_queue = true;
else if ((ring->funcs->type == AMDGPU_RING_TYPE_GFX) &&
adev->mes.gfx_pipe_reset_enabled)
reinit_queue = true;
else
reinit_queue = use_mmio;
amdgpu_ring_reset_helper_begin(ring, timedout_fence);
r = amdgpu_mes_reset_legacy_queue(ring->adev, ring, vmid, use_mmio, 0);
if (r)
return r;
if (reinit_queue) {
r = amdgpu_mes_unmap_legacy_queue(adev, ring,
RESET_QUEUES, 0, 0, 0);
if (r)
return r;
amdgpu_gfx_mqd_reset_restore(ring);
r = amdgpu_mes_map_legacy_queue(adev, ring, 0);
if (r) {
dev_err(adev->dev, "failed to remap kgq\n");
return r;
}
}
return 0;
}
int amdgpu_gfx_mes_reset_queue(struct amdgpu_ring *ring,
unsigned int vmid,
struct amdgpu_fence *timedout_fence,
bool use_mmio)
{
int r;
r = amdgpu_gfx_mes_reset_queue_start(ring, vmid, timedout_fence,
use_mmio);
if (r)
return r;
return amdgpu_ring_reset_helper_end(ring, timedout_fence);
}
static DEVICE_ATTR(run_cleaner_shader, 0200,
NULL, amdgpu_gfx_set_run_cleaner_shader);
@@ -2122,6 +2201,200 @@ void amdgpu_gfx_sysfs_fini(struct amdgpu_device *adev)
}
}
static void amdgpu_gfx_reset_start_compute_scheds(struct amdgpu_device *adev,
struct amdgpu_ring *guilty_ring)
{
struct amdgpu_ring *ring;
int i;
for (i = 0; i < adev->gfx.num_compute_rings; i++) {
ring = &adev->gfx.compute_ring[i];
if (ring == guilty_ring)
continue;
drm_sched_wqueue_start(&ring->sched);
}
}
static void amdgpu_gfx_reset_stop_compute_scheds(struct amdgpu_device *adev,
struct amdgpu_ring *guilty_ring)
{
struct amdgpu_ring *ring;
int i;
for (i = 0; i < adev->gfx.num_compute_rings; i++) {
ring = &adev->gfx.compute_ring[i];
if (ring == guilty_ring)
continue;
drm_sched_wqueue_stop(&ring->sched);
}
}
/*
* Match the MES-reported hung doorbell against a compute ring and run
* the reset. On hit, the matched ring and its guilty fence are returned
* via *out_ring / *out_fence so the caller can defer reset end until
* after MES has resumed all gangs.
*/
static int amdgpu_gfx_reset_mes_kcq(struct amdgpu_device *adev,
struct amdgpu_ring *guilty_ring,
unsigned int db,
struct amdgpu_ring **out_ring,
struct amdgpu_fence **out_fence)
{
bool use_mmio = adev->gfx.mec.use_mmio_for_reset;
struct amdgpu_fence *fence;
struct amdgpu_ring *ring;
int i, r;
*out_ring = NULL;
*out_fence = NULL;
for (i = 0; i < adev->gfx.num_compute_rings; i++) {
ring = &adev->gfx.compute_ring[i];
if (ring == guilty_ring)
continue;
if (ring->doorbell_index == db) {
fence = amdgpu_ring_find_guilty_fence(ring);
r = amdgpu_gfx_mes_reset_queue_start(ring, 0, fence,
use_mmio);
if (r)
return r;
*out_ring = ring;
*out_fence = fence;
break;
}
}
return 0;
}
int amdgpu_gfx_reset_mes_compute(struct amdgpu_device *adev,
struct amdgpu_ring *ring,
struct amdgpu_fence *guilty_fence,
struct amdgpu_usermode_queue *uq,
unsigned int *hung_queue_count,
void *faulty_queue_input)
{
struct amdgpu_mes_hung_queue_hqd_info *hqd_info =
(struct amdgpu_mes_hung_queue_hqd_info *)
&adev->gfx.mec.mes_hung_db_array[adev->mes.hung_queue_hqd_info_offset];
int i, r, pipe, queue, queue_type;
unsigned int num_hung = 0;
bool use_mmio = adev->gfx.mec.use_mmio_for_reset;
struct mes_remove_queue_input *queue_input = (struct mes_remove_queue_input *)faulty_queue_input;
struct amdgpu_gfx_deferred_entry deferred_end[AMDGPU_MAX_COMPUTE_RINGS + 1];
int n_deferred = 0;
int ring_err;
guard(mutex)(&adev->gfx.mec.reset_mutex);
/* stop the drm schedulers for all compute queues */
amdgpu_gfx_reset_stop_compute_scheds(adev, ring);
/* suspend all will determine which queues are hung.
* reset detect will return the array of bad queue doorbells
*/
r = amdgpu_mes_suspend(adev, 0);
/* if suspend all success, it should no hang queue */
if (!r)
/* always reset the KCQ/userq since we need to signal the fence
* and we could be stuck in a loop which is preemptable.
*/
goto fence_reset;
r = amdgpu_mes_detect_and_reset_hung_queues(adev, AMDGPU_RING_TYPE_COMPUTE,
true, &num_hung, adev->gfx.mec.mes_hung_db_array, 0);
if (r)
goto out;
if (hung_queue_count)
*hung_queue_count = num_hung;
fence_reset:
/* reset the queue this came from if specified */
if (ring) {
r = amdgpu_gfx_mes_reset_queue_start(ring, 0, guilty_fence,
use_mmio);
if (r)
goto out;
deferred_end[n_deferred].ring = ring;
deferred_end[n_deferred].fence = guilty_fence;
n_deferred++;
}
if (uq) {
r = mes_userq_reset(uq);
if (r)
goto out;
}
for (i = 0; i < num_hung; i++) {
struct amdgpu_ring *hr = NULL;
struct amdgpu_fence *hf = NULL;
pipe = hqd_info[i].pipe_index;
queue = hqd_info[i].queue_index;
queue_type = hqd_info[i].queue_type;
/* reset any KCQs */
r = amdgpu_gfx_reset_mes_kcq(adev, ring,
adev->gfx.mec.mes_hung_db_array[i],
&hr, &hf);
if (r)
goto out;
if (hr) {
deferred_end[n_deferred].ring = hr;
deferred_end[n_deferred].fence = hf;
n_deferred++;
}
/* reset any KFD queues */
r = amdgpu_amdkfd_reset_mes_queue(adev, 0, queue_type, pipe, queue,
adev->gfx.mec.mes_hung_db_array[i]);
if (r)
goto out;
/* reset KGD user queues */
r = mes_userq_reset_queue(adev, uq, queue_type, pipe, queue,
adev->gfx.mec.mes_hung_db_array[i]);
if (r)
goto out;
}
/* MES doesn't detect any hung queue but we have a known bad queue
* and it is not KCQ
*/
if (!num_hung && queue_input && !ring) {
/* MES suspend_all is successful means this bad queue is
* preempted successfuly. Remove it before resume all so it
* doesn't get mapped back
*/
if (!down_read_trylock(&adev->reset_domain->sem)) {
r = -EIO;
goto out;
}
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);
}
out:
/* resume all will enable the non-hung queues */
amdgpu_mes_resume(adev, 0);
/* Now CP is running again — replay backed-up commands and ring
* doorbells on each reset queue.
*/
ring_err = r;
for (i = 0; i < n_deferred; i++) {
int er = amdgpu_ring_reset_helper_end(deferred_end[i].ring,
deferred_end[i].fence);
if (er && !ring_err)
ring_err = er;
}
if (!ring_err)
amdgpu_gfx_reset_start_compute_scheds(adev, ring);
/* If this reset is triggered by non-KCQ, the KCQ result after resume must
* not override the reset result; otherwise a false reset failure is returned
* to the non-KCQ caller
*/
return ring ? ring_err : r;
}
int amdgpu_gfx_cleaner_shader_sw_init(struct amdgpu_device *adev,
unsigned int cleaner_shader_size)
{
@@ -2460,9 +2733,8 @@ void amdgpu_gfx_profile_ring_begin_use(struct amdgpu_ring *ring)
else
profile = PP_SMC_POWER_PROFILE_COMPUTE;
atomic_inc(&adev->gfx.total_submission_cnt);
cancel_delayed_work_sync(&adev->gfx.idle_work);
if (!atomic_fetch_inc(&adev->gfx.total_submission_cnt))
cancel_delayed_work_sync(&adev->gfx.idle_work);
/* We can safely return early here because we've cancelled the
* the delayed work so there is no one else to set it to false
@@ -2490,9 +2762,9 @@ void amdgpu_gfx_profile_ring_end_use(struct amdgpu_ring *ring)
if (amdgpu_dpm_is_overdrive_enabled(adev))
return;
atomic_dec(&ring->adev->gfx.total_submission_cnt);
schedule_delayed_work(&ring->adev->gfx.idle_work, GFX_PROFILE_IDLE_TIMEOUT);
if (atomic_dec_and_test(&ring->adev->gfx.total_submission_cnt))
schedule_delayed_work(&ring->adev->gfx.idle_work,
GFX_PROFILE_IDLE_TIMEOUT);
}
/**

View File

@@ -36,6 +36,8 @@
#include "amdgpu_ring_mux.h"
#include "amdgpu_xcp.h"
struct amdgpu_usermode_queue;
/* GFX current status */
#define AMDGPU_GFX_NORMAL_MODE 0x00000000L
#define AMDGPU_GFX_SAFE_MODE 0x00000001L
@@ -116,6 +118,9 @@ struct amdgpu_mec {
u32 num_pipe_per_mec;
u32 num_queue_per_pipe;
void *mqd_backup[AMDGPU_MAX_COMPUTE_RINGS * AMDGPU_MAX_GC_INSTANCES];
bool use_mmio_for_reset;
u32 *mes_hung_db_array;
struct mutex reset_mutex;
};
struct amdgpu_mec_bitmap {
@@ -401,6 +406,7 @@ struct amdgpu_me {
uint32_t num_pipe_per_me;
uint32_t num_queue_per_pipe;
void *mqd_backup[AMDGPU_MAX_GFX_RINGS];
bool use_mmio_for_reset;
/* These are the resources for which amdgpu takes ownership */
DECLARE_BITMAP(queue_bitmap, AMDGPU_MAX_GFX_QUEUES);
@@ -479,8 +485,6 @@ struct amdgpu_gfx {
const struct amdgpu_gfx_funcs *funcs;
/* reset mask */
uint32_t grbm_soft_reset;
uint32_t srbm_soft_reset;
uint32_t gfx_supported_reset;
uint32_t compute_supported_reset;
@@ -543,6 +547,11 @@ struct amdgpu_gfx {
bool disable_uq;
};
struct amdgpu_gfx_deferred_entry {
struct amdgpu_ring *ring;
struct amdgpu_fence *fence;
};
struct amdgpu_gfx_ras_reg_entry {
struct amdgpu_ras_err_status_reg_entry reg_entry;
enum amdgpu_gfx_ras_mem_id_type mem_id_type;
@@ -641,6 +650,12 @@ int amdgpu_gfx_poison_consumption_handler(struct amdgpu_device *adev,
bool amdgpu_gfx_is_master_xcc(struct amdgpu_device *adev, int xcc_id);
int amdgpu_gfx_sysfs_init(struct amdgpu_device *adev);
void amdgpu_gfx_sysfs_fini(struct amdgpu_device *adev);
int amdgpu_gfx_reset_mes_compute(struct amdgpu_device *adev,
struct amdgpu_ring *ring,
struct amdgpu_fence *guilty_fence,
struct amdgpu_usermode_queue *uq,
unsigned int *hung_queue_count,
void *faulty_queue_input);
void amdgpu_gfx_ras_error_func(struct amdgpu_device *adev,
void *ras_error_status,
void (*func)(struct amdgpu_device *adev, void *ras_error_status,
@@ -667,6 +682,11 @@ void amdgpu_debugfs_compute_sched_mask_init(struct amdgpu_device *adev);
int amdgpu_gfx_ring_preempt_ib(struct amdgpu_ring *ring);
int amdgpu_gfx_mes_reset_queue(struct amdgpu_ring *ring,
unsigned int vmid,
struct amdgpu_fence *timedout_fence,
bool use_mmio);
static inline const char *amdgpu_gfx_compute_mode_desc(int mode)
{
switch (mode) {

View File

@@ -1763,10 +1763,15 @@ int amdgpu_gmc_init_mem_ranges(struct amdgpu_device *adev)
valid = true;
else
valid = amdgpu_gmc_validate_partition_info(adev);
if (!valid) {
/* TODO: handle invalid case */
if (!valid)
dev_warn(adev->dev,
"Mem ranges not matching with hardware config\n");
if (!adev->gmc.num_mem_partitions) {
dev_err(adev->dev, "num_mem_partitions is zero\n");
kfree(adev->gmc.mem_partitions);
adev->gmc.mem_partitions = NULL;
return -EINVAL;
}
return 0;

View File

@@ -286,7 +286,6 @@ struct amdgpu_gmc {
struct amdgpu_irq_src vm_fault;
uint32_t vram_type;
uint8_t vram_vendor;
uint32_t srbm_soft_reset;
bool prt_warning;
uint32_t sdpif_register;
/* apertures */

View File

@@ -368,27 +368,6 @@ int amdgpu_device_ip_wait_for_idle(struct amdgpu_device *adev,
return 0;
}
/**
* amdgpu_device_ip_is_hw - is the hardware IP enabled
*
* @adev: amdgpu_device pointer
* @block_type: Type of hardware IP (SMU, GFX, UVD, etc.)
*
* Check if the hardware IP is enable or not.
* Returns true if it the IP is enable, false if not.
*/
bool amdgpu_device_ip_is_hw(struct amdgpu_device *adev,
enum amd_ip_block_type block_type)
{
struct amdgpu_ip_block *ip_block;
ip_block = amdgpu_device_ip_get_ip_block(adev, block_type);
if (ip_block)
return ip_block->status.hw;
return false;
}
/**
* amdgpu_device_ip_is_valid - is the hardware IP valid
*
@@ -409,3 +388,133 @@ bool amdgpu_device_ip_is_valid(struct amdgpu_device *adev,
return false;
}
/**
* amdgpu_ip_from_ring() - Find IP block type corresponding to ring type.
*
* @ring_type: The ring type whose IP block you are looking for.
*/
static enum amd_ip_block_type amdgpu_ip_from_ring(const enum amdgpu_ring_type ring_type)
{
switch (ring_type) {
case AMDGPU_RING_TYPE_GFX:
case AMDGPU_RING_TYPE_COMPUTE:
return AMD_IP_BLOCK_TYPE_GFX;
case AMDGPU_RING_TYPE_SDMA:
return AMD_IP_BLOCK_TYPE_SDMA;
case AMDGPU_RING_TYPE_UVD:
case AMDGPU_RING_TYPE_UVD_ENC:
return AMD_IP_BLOCK_TYPE_UVD;
case AMDGPU_RING_TYPE_VCE:
return AMD_IP_BLOCK_TYPE_VCE;
case AMDGPU_RING_TYPE_VCN_DEC:
case AMDGPU_RING_TYPE_VCN_ENC:
return AMD_IP_BLOCK_TYPE_VCN;
case AMDGPU_RING_TYPE_VCN_JPEG:
return AMD_IP_BLOCK_TYPE_JPEG;
case AMDGPU_RING_TYPE_VPE:
return AMD_IP_BLOCK_TYPE_VPE;
default:
return AMD_IP_BLOCK_TYPE_NUM;
}
}
/**
* amdgpu_ring_mask_from_ip() - Find mask of ring types corresponding to an IP block type.
*
* @ip_type: The IP block type whose rings you are looking for.
*/
static u32 amdgpu_ring_mask_from_ip(const enum amd_ip_block_type ip_type)
{
switch (ip_type) {
case AMD_IP_BLOCK_TYPE_GFX:
return BIT(AMDGPU_RING_TYPE_GFX) | BIT(AMDGPU_RING_TYPE_COMPUTE);
case AMD_IP_BLOCK_TYPE_SDMA:
return BIT(AMDGPU_RING_TYPE_SDMA);
case AMD_IP_BLOCK_TYPE_UVD:
return BIT(AMDGPU_RING_TYPE_UVD) | BIT(AMDGPU_RING_TYPE_UVD_ENC);
case AMD_IP_BLOCK_TYPE_VCE:
return BIT(AMD_IP_BLOCK_TYPE_VCE);
case AMD_IP_BLOCK_TYPE_VCN:
return BIT(AMDGPU_RING_TYPE_VCN_DEC) | BIT(AMDGPU_RING_TYPE_VCN_ENC);
case AMD_IP_BLOCK_TYPE_JPEG:
return BIT(AMDGPU_RING_TYPE_VCN_JPEG);
case AMD_IP_BLOCK_TYPE_VPE:
return BIT(AMDGPU_RING_TYPE_VPE);
default:
return 0;
}
}
/**
* amdgpu_device_ip_soft_reset() - Perform a graceful soft reset on an IP block.
*
* @guilty_ring: The ring which is guilty of causing a reset.
* @guilty_fence: The fence which didn't signal.
*
* IP block soft reset is used when attempting to recover
* from a GPU hang in a situation where a more fine grained
* reset type isn't available or didn't work. This effectively
* resets all rings that belong to the same device IP block
* and re-initializes the device IP block.
*
* The reset is handled gracefully, meaning that we try to
* minimize collateral damage (ie. avoid rejecting non-guilty jobs)
* as well as back up and restore the contents of all rings
* so that the system can move on from the hang.
*/
int amdgpu_device_ip_soft_reset(struct amdgpu_ring *guilty_ring,
struct amdgpu_fence *guilty_fence)
{
struct amdgpu_device *adev = guilty_ring->adev;
struct amdgpu_ip_block *ip_block;
enum amd_ip_block_type ip_type;
u32 ring_type_mask;
int r;
ip_type = amdgpu_ip_from_ring(guilty_ring->funcs->type);
ip_block = amdgpu_device_ip_get_ip_block(adev, ip_type);
if (!ip_block || !ip_block->version->funcs->soft_reset) {
dev_warn(adev->dev, "IP block soft reset not supported on %s\n",
ip_block->version->funcs->name);
return -EOPNOTSUPP;
}
dev_err(adev->dev, "Starting %s IP block soft reset\n",
ip_block->version->funcs->name);
ring_type_mask = amdgpu_ring_mask_from_ip(ip_type);
amdgpu_device_lock_reset_domain(adev->reset_domain);
amdgpu_multi_ring_reset_helper_begin(ring_type_mask, guilty_ring, guilty_fence);
r = ip_block->version->funcs->soft_reset(ip_block);
r = amdgpu_multi_ring_reset_helper_end(ring_type_mask, guilty_ring, r);
amdgpu_device_unlock_reset_domain(adev->reset_domain);
if (r) {
dev_err(adev->dev, "Failed %s IP block soft reset: %d\n",
ip_block->version->funcs->name, r);
return r;
}
dev_err(adev->dev, "Successful %s IP block soft reset\n",
ip_block->version->funcs->name);
return 0;
}

View File

@@ -68,6 +68,7 @@ enum amd_hw_ip_block_type {
ISP_HWIP,
ATU_HWIP,
AIGC_HWIP,
UMSCH_HWIP,
MAX_HWIP
};
@@ -84,6 +85,9 @@ enum amd_hw_ip_block_type {
#define IP_VERSION_SUBREV(ver) ((ver) & 0xF)
#define IP_VERSION_MAJ_MIN_REV(ver) ((ver) >> 8)
struct amdgpu_ring;
struct amdgpu_fence;
struct amdgpu_ip_map_info {
/* Map of logical to actual dev instances/mask */
uint32_t dev_inst[MAX_HWIP][HWIP_MAX_INSTANCE];
@@ -146,9 +150,9 @@ void amdgpu_device_ip_get_clockgating_state(struct amdgpu_device *adev,
u64 *flags);
int amdgpu_device_ip_wait_for_idle(struct amdgpu_device *adev,
enum amd_ip_block_type block_type);
bool amdgpu_device_ip_is_hw(struct amdgpu_device *adev,
enum amd_ip_block_type block_type);
bool amdgpu_device_ip_is_valid(struct amdgpu_device *adev,
enum amd_ip_block_type block_type);
int amdgpu_device_ip_soft_reset(struct amdgpu_ring *guilty_ring,
struct amdgpu_fence *guilty_fence);
#endif /* __AMDGPU_IP_H__ */

View File

@@ -112,7 +112,7 @@ static enum drm_gpu_sched_stat amdgpu_job_timedout(struct drm_sched_job *s_job)
amdgpu_job_core_dump(adev, job);
if (amdgpu_gpu_recovery &&
amdgpu_ring_is_reset_type_supported(ring, AMDGPU_RESET_TYPE_SOFT_RESET) &&
amdgpu_ring_is_reset_type_supported(ring, AMDGPU_RESET_TYPE_SOFT_RECOVERY) &&
amdgpu_ring_soft_recovery(ring, job->vmid, s_job->s_fence->parent)) {
dev_err(adev->dev, "ring %s timeout, but soft recovered\n",
s_job->sched->name);
@@ -151,6 +151,17 @@ static enum drm_gpu_sched_stat amdgpu_job_timedout(struct drm_sched_job *s_job)
dev_err(adev->dev, "Ring %s reset failed\n", ring->sched.name);
}
/* Attempt an IP block soft reset, if supported. */
if (amdgpu_gpu_recovery &&
amdgpu_ring_is_reset_type_supported(ring, AMDGPU_RESET_TYPE_IP_BLOCK_SOFT_RESET)) {
r = amdgpu_device_ip_soft_reset(ring, job->hw_fence);
if (!r) {
atomic_inc(&ring->adev->gpu_reset_counter);
drm_dev_wedged_event(adev_to_drm(adev), DRM_WEDGE_RECOVERY_NONE, info);
goto exit;
}
}
if (dma_fence_get_status(&s_job->s_fence->finished) == 0)
dma_fence_set_error(&s_job->s_fence->finished, -ETIME);

View File

@@ -134,8 +134,8 @@ void amdgpu_jpeg_ring_begin_use(struct amdgpu_ring *ring)
{
struct amdgpu_device *adev = ring->adev;
atomic_inc(&adev->jpeg.total_submission_cnt);
cancel_delayed_work_sync(&adev->jpeg.idle_work);
if (!atomic_fetch_inc(&adev->jpeg.total_submission_cnt))
cancel_delayed_work_sync(&adev->jpeg.idle_work);
mutex_lock(&adev->jpeg.jpeg_pg_lock);
amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_JPEG,
@@ -145,8 +145,9 @@ void amdgpu_jpeg_ring_begin_use(struct amdgpu_ring *ring)
void amdgpu_jpeg_ring_end_use(struct amdgpu_ring *ring)
{
atomic_dec(&ring->adev->jpeg.total_submission_cnt);
schedule_delayed_work(&ring->adev->jpeg.idle_work, JPEG_IDLE_TIMEOUT);
if (atomic_dec_and_test(&ring->adev->jpeg.total_submission_cnt))
schedule_delayed_work(&ring->adev->jpeg.idle_work,
JPEG_IDLE_TIMEOUT);
}
int amdgpu_jpeg_dec_ring_test_ring(struct amdgpu_ring *ring)

View File

@@ -149,6 +149,9 @@ struct amdgpu_jpeg {
u32 *ip_dump;
u32 reg_count;
const struct amdgpu_hwip_reg_entry *reg_list;
bool disable_uq;
bool disable_kq;
};
int amdgpu_jpeg_sw_init(struct amdgpu_device *adev);

View File

@@ -1423,6 +1423,33 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
return 0;
}
/**
* amdgpu_proc_options_ioctl - set per-fd user options
*
* @dev: drm dev pointer
* @data: pointer to struct drm_amdgpu_proc_options
* @filp: drm file
*
* Sets options stored on the per-file amdgpu_fpriv. Currently the only
* supported option is %AMDGPU_PROC_OPTIONS_OP_KFD_SIGBUS_DELAY which
* controls how KFD delivers SIGBUS for poison/RAS events to the calling
* process (immediate, suppressed, or delayed by N milliseconds).
*/
int amdgpu_proc_options_ioctl(struct drm_device *dev, void *data,
struct drm_file *filp)
{
struct drm_amdgpu_proc_options *args = data;
switch (args->op) {
case AMDGPU_PROC_OPTIONS_OP_KFD_SIGBUS_DELAY:
return amdgpu_amdkfd_set_sigbus_delay(current,
args->kfd_sigbus_delay.value);
default:
DRM_DEBUG_KMS("Invalid user option op %u\n", args->op);
return -EINVAL;
}
}
/**
* amdgpu_driver_open_kms - drm callback for open
*
@@ -1504,8 +1531,7 @@ int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv)
if (r)
goto error_vm;
mutex_init(&fpriv->bo_list_lock);
idr_init_base(&fpriv->bo_list_handles, 1);
xa_init_flags(&fpriv->bo_list_handles, XA_FLAGS_ALLOC1);
r = amdgpu_userq_mgr_init(&fpriv->userq_mgr, file_priv, adev);
if (r)
@@ -1550,8 +1576,8 @@ void amdgpu_driver_postclose_kms(struct drm_device *dev,
struct amdgpu_fpriv *fpriv = file_priv->driver_priv;
struct amdgpu_bo_list *list;
struct amdgpu_bo *pd;
unsigned long handle;
u32 pasid;
int handle;
if (!fpriv)
return;
@@ -1587,11 +1613,9 @@ void amdgpu_driver_postclose_kms(struct drm_device *dev,
amdgpu_pasid_free_delayed(pd->tbo.base.resv, pasid);
amdgpu_bo_unref(&pd);
idr_for_each_entry(&fpriv->bo_list_handles, list, handle)
xa_for_each(&fpriv->bo_list_handles, handle, list)
amdgpu_bo_list_put(list);
idr_destroy(&fpriv->bo_list_handles);
mutex_destroy(&fpriv->bo_list_lock);
xa_destroy(&fpriv->bo_list_handles);
kfree(fpriv);
file_priv->driver_priv = NULL;

View File

@@ -27,16 +27,6 @@
#include "umc/umc_6_7_0_offset.h"
#include "umc/umc_6_7_0_sh_mask.h"
static bool amdgpu_mca_is_deferred_error(struct amdgpu_device *adev,
uint64_t mc_status)
{
if (adev->umc.ras->check_ecc_err_status)
return adev->umc.ras->check_ecc_err_status(adev,
AMDGPU_MCA_ERROR_TYPE_DE, &mc_status);
return false;
}
void amdgpu_mca_query_correctable_error_count(struct amdgpu_device *adev,
uint64_t mc_status_addr,
unsigned long *error_count)
@@ -155,479 +145,3 @@ int amdgpu_mca_mpio_ras_sw_init(struct amdgpu_device *adev)
return 0;
}
static void amdgpu_mca_bank_set_init(struct mca_bank_set *mca_set)
{
if (!mca_set)
return;
memset(mca_set, 0, sizeof(*mca_set));
INIT_LIST_HEAD(&mca_set->list);
}
static int amdgpu_mca_bank_set_add_entry(struct mca_bank_set *mca_set, struct mca_bank_entry *entry)
{
struct mca_bank_node *node;
if (!entry)
return -EINVAL;
node = kvzalloc_obj(*node);
if (!node)
return -ENOMEM;
memcpy(&node->entry, entry, sizeof(*entry));
INIT_LIST_HEAD(&node->node);
list_add_tail(&node->node, &mca_set->list);
mca_set->nr_entries++;
return 0;
}
static int amdgpu_mca_bank_set_merge(struct mca_bank_set *mca_set, struct mca_bank_set *new)
{
struct mca_bank_node *node;
list_for_each_entry(node, &new->list, node)
amdgpu_mca_bank_set_add_entry(mca_set, &node->entry);
return 0;
}
static void amdgpu_mca_bank_set_remove_node(struct mca_bank_set *mca_set, struct mca_bank_node *node)
{
if (!node)
return;
list_del(&node->node);
kvfree(node);
mca_set->nr_entries--;
}
static void amdgpu_mca_bank_set_release(struct mca_bank_set *mca_set)
{
struct mca_bank_node *node, *tmp;
if (list_empty(&mca_set->list))
return;
list_for_each_entry_safe(node, tmp, &mca_set->list, node)
amdgpu_mca_bank_set_remove_node(mca_set, node);
}
void amdgpu_mca_smu_init_funcs(struct amdgpu_device *adev, const struct amdgpu_mca_smu_funcs *mca_funcs)
{
struct amdgpu_mca *mca = &adev->mca;
mca->mca_funcs = mca_funcs;
}
int amdgpu_mca_init(struct amdgpu_device *adev)
{
struct amdgpu_mca *mca = &adev->mca;
struct mca_bank_cache *mca_cache;
int i;
atomic_set(&mca->ue_update_flag, 0);
for (i = 0; i < ARRAY_SIZE(mca->mca_caches); i++) {
mca_cache = &mca->mca_caches[i];
mutex_init(&mca_cache->lock);
amdgpu_mca_bank_set_init(&mca_cache->mca_set);
}
return 0;
}
void amdgpu_mca_fini(struct amdgpu_device *adev)
{
struct amdgpu_mca *mca = &adev->mca;
struct mca_bank_cache *mca_cache;
int i;
atomic_set(&mca->ue_update_flag, 0);
for (i = 0; i < ARRAY_SIZE(mca->mca_caches); i++) {
mca_cache = &mca->mca_caches[i];
amdgpu_mca_bank_set_release(&mca_cache->mca_set);
mutex_destroy(&mca_cache->lock);
}
}
int amdgpu_mca_reset(struct amdgpu_device *adev)
{
amdgpu_mca_fini(adev);
return amdgpu_mca_init(adev);
}
int amdgpu_mca_smu_set_debug_mode(struct amdgpu_device *adev, bool enable)
{
const struct amdgpu_mca_smu_funcs *mca_funcs = adev->mca.mca_funcs;
if (mca_funcs && mca_funcs->mca_set_debug_mode)
return mca_funcs->mca_set_debug_mode(adev, enable);
return -EOPNOTSUPP;
}
static void amdgpu_mca_smu_mca_bank_dump(struct amdgpu_device *adev, int idx, struct mca_bank_entry *entry,
struct ras_query_context *qctx)
{
u64 event_id = qctx ? qctx->evid.event_id : RAS_EVENT_INVALID_ID;
RAS_EVENT_LOG(adev, event_id, HW_ERR "Accelerator Check Architecture events logged\n");
RAS_EVENT_LOG(adev, event_id, HW_ERR "aca entry[%02d].STATUS=0x%016llx\n",
idx, entry->regs[MCA_REG_IDX_STATUS]);
RAS_EVENT_LOG(adev, event_id, HW_ERR "aca entry[%02d].ADDR=0x%016llx\n",
idx, entry->regs[MCA_REG_IDX_ADDR]);
RAS_EVENT_LOG(adev, event_id, HW_ERR "aca entry[%02d].MISC0=0x%016llx\n",
idx, entry->regs[MCA_REG_IDX_MISC0]);
RAS_EVENT_LOG(adev, event_id, HW_ERR "aca entry[%02d].IPID=0x%016llx\n",
idx, entry->regs[MCA_REG_IDX_IPID]);
RAS_EVENT_LOG(adev, event_id, HW_ERR "aca entry[%02d].SYND=0x%016llx\n",
idx, entry->regs[MCA_REG_IDX_SYND]);
}
static int amdgpu_mca_smu_get_valid_mca_count(struct amdgpu_device *adev, enum amdgpu_mca_error_type type, uint32_t *count)
{
const struct amdgpu_mca_smu_funcs *mca_funcs = adev->mca.mca_funcs;
if (!count)
return -EINVAL;
if (mca_funcs && mca_funcs->mca_get_valid_mca_count)
return mca_funcs->mca_get_valid_mca_count(adev, type, count);
return -EOPNOTSUPP;
}
static int amdgpu_mca_smu_get_mca_entry(struct amdgpu_device *adev, enum amdgpu_mca_error_type type,
int idx, struct mca_bank_entry *entry)
{
const struct amdgpu_mca_smu_funcs *mca_funcs = adev->mca.mca_funcs;
int count;
if (!mca_funcs || !mca_funcs->mca_get_mca_entry)
return -EOPNOTSUPP;
switch (type) {
case AMDGPU_MCA_ERROR_TYPE_UE:
count = mca_funcs->max_ue_count;
break;
case AMDGPU_MCA_ERROR_TYPE_CE:
count = mca_funcs->max_ce_count;
break;
default:
return -EINVAL;
}
if (idx >= count)
return -EINVAL;
return mca_funcs->mca_get_mca_entry(adev, type, idx, entry);
}
static bool amdgpu_mca_bank_should_update(struct amdgpu_device *adev, enum amdgpu_mca_error_type type)
{
struct amdgpu_mca *mca = &adev->mca;
bool ret = true;
/*
* Because the UE Valid MCA count will only be cleared after reset,
* in order to avoid repeated counting of the error count,
* the aca bank is only updated once during the gpu recovery stage.
*/
if (type == AMDGPU_MCA_ERROR_TYPE_UE) {
if (amdgpu_ras_intr_triggered())
ret = atomic_cmpxchg(&mca->ue_update_flag, 0, 1) == 0;
else
atomic_set(&mca->ue_update_flag, 0);
}
return ret;
}
static bool amdgpu_mca_bank_should_dump(struct amdgpu_device *adev, enum amdgpu_mca_error_type type,
struct mca_bank_entry *entry)
{
bool ret;
switch (type) {
case AMDGPU_MCA_ERROR_TYPE_CE:
ret = amdgpu_mca_is_deferred_error(adev, entry->regs[MCA_REG_IDX_STATUS]);
break;
case AMDGPU_MCA_ERROR_TYPE_UE:
default:
ret = true;
break;
}
return ret;
}
static int amdgpu_mca_smu_get_mca_set(struct amdgpu_device *adev, enum amdgpu_mca_error_type type, struct mca_bank_set *mca_set,
struct ras_query_context *qctx)
{
struct mca_bank_entry entry;
uint32_t count = 0, i;
int ret;
if (!mca_set)
return -EINVAL;
if (!amdgpu_mca_bank_should_update(adev, type))
return 0;
ret = amdgpu_mca_smu_get_valid_mca_count(adev, type, &count);
if (ret)
return ret;
for (i = 0; i < count; i++) {
memset(&entry, 0, sizeof(entry));
ret = amdgpu_mca_smu_get_mca_entry(adev, type, i, &entry);
if (ret)
return ret;
amdgpu_mca_bank_set_add_entry(mca_set, &entry);
if (amdgpu_mca_bank_should_dump(adev, type, &entry))
amdgpu_mca_smu_mca_bank_dump(adev, i, &entry, qctx);
}
return 0;
}
static int amdgpu_mca_smu_parse_mca_error_count(struct amdgpu_device *adev, enum amdgpu_ras_block blk,
enum amdgpu_mca_error_type type, struct mca_bank_entry *entry, uint32_t *count)
{
const struct amdgpu_mca_smu_funcs *mca_funcs = adev->mca.mca_funcs;
if (!count || !entry)
return -EINVAL;
if (!mca_funcs || !mca_funcs->mca_parse_mca_error_count)
return -EOPNOTSUPP;
return mca_funcs->mca_parse_mca_error_count(adev, blk, type, entry, count);
}
static int amdgpu_mca_dispatch_mca_set(struct amdgpu_device *adev, enum amdgpu_ras_block blk, enum amdgpu_mca_error_type type,
struct mca_bank_set *mca_set, struct ras_err_data *err_data)
{
struct amdgpu_smuio_mcm_config_info mcm_info;
struct mca_bank_node *node, *tmp;
struct mca_bank_entry *entry;
uint32_t count;
int ret;
if (!mca_set)
return -EINVAL;
if (!mca_set->nr_entries)
return 0;
list_for_each_entry_safe(node, tmp, &mca_set->list, node) {
entry = &node->entry;
count = 0;
ret = amdgpu_mca_smu_parse_mca_error_count(adev, blk, type, entry, &count);
if (ret && ret != -EOPNOTSUPP)
return ret;
if (!count)
continue;
memset(&mcm_info, 0, sizeof(mcm_info));
mcm_info.socket_id = entry->info.socket_id;
mcm_info.die_id = entry->info.aid;
if (type == AMDGPU_MCA_ERROR_TYPE_UE) {
amdgpu_ras_error_statistic_ue_count(err_data,
&mcm_info, (uint64_t)count);
} else {
if (amdgpu_mca_is_deferred_error(adev, entry->regs[MCA_REG_IDX_STATUS]))
amdgpu_ras_error_statistic_de_count(err_data,
&mcm_info, (uint64_t)count);
else
amdgpu_ras_error_statistic_ce_count(err_data,
&mcm_info, (uint64_t)count);
}
amdgpu_mca_bank_set_remove_node(mca_set, node);
}
return 0;
}
static int amdgpu_mca_add_mca_set_to_cache(struct amdgpu_device *adev, enum amdgpu_mca_error_type type, struct mca_bank_set *new)
{
struct mca_bank_cache *mca_cache = &adev->mca.mca_caches[type];
int ret;
mutex_lock(&mca_cache->lock);
ret = amdgpu_mca_bank_set_merge(&mca_cache->mca_set, new);
mutex_unlock(&mca_cache->lock);
return ret;
}
int amdgpu_mca_smu_log_ras_error(struct amdgpu_device *adev, enum amdgpu_ras_block blk, enum amdgpu_mca_error_type type,
struct ras_err_data *err_data, struct ras_query_context *qctx)
{
struct mca_bank_set mca_set;
struct mca_bank_cache *mca_cache = &adev->mca.mca_caches[type];
int ret;
amdgpu_mca_bank_set_init(&mca_set);
ret = amdgpu_mca_smu_get_mca_set(adev, type, &mca_set, qctx);
if (ret)
goto out_mca_release;
ret = amdgpu_mca_dispatch_mca_set(adev, blk, type, &mca_set, err_data);
if (ret)
goto out_mca_release;
/* add remain mca bank to mca cache */
if (mca_set.nr_entries) {
ret = amdgpu_mca_add_mca_set_to_cache(adev, type, &mca_set);
if (ret)
goto out_mca_release;
}
/* dispatch mca set again if mca cache has valid data */
mutex_lock(&mca_cache->lock);
if (mca_cache->mca_set.nr_entries)
ret = amdgpu_mca_dispatch_mca_set(adev, blk, type, &mca_cache->mca_set, err_data);
mutex_unlock(&mca_cache->lock);
out_mca_release:
amdgpu_mca_bank_set_release(&mca_set);
return ret;
}
#if defined(CONFIG_DEBUG_FS)
static int amdgpu_mca_smu_debug_mode_set(void *data, u64 val)
{
struct amdgpu_device *adev = (struct amdgpu_device *)data;
int ret;
ret = amdgpu_ras_set_mca_debug_mode(adev, val ? true : false);
if (ret)
return ret;
dev_info(adev->dev, "amdgpu set smu mca debug mode %s success\n", val ? "on" : "off");
return 0;
}
static void mca_dump_entry(struct seq_file *m, struct mca_bank_entry *entry)
{
int i, idx = entry->idx;
int reg_idx_array[] = {
MCA_REG_IDX_STATUS,
MCA_REG_IDX_ADDR,
MCA_REG_IDX_MISC0,
MCA_REG_IDX_IPID,
MCA_REG_IDX_SYND,
};
seq_printf(m, "mca entry[%d].type: %s\n", idx, entry->type == AMDGPU_MCA_ERROR_TYPE_UE ? "UE" : "CE");
seq_printf(m, "mca entry[%d].ip: %d\n", idx, entry->ip);
seq_printf(m, "mca entry[%d].info: socketid:%d aid:%d hwid:0x%03x mcatype:0x%04x\n",
idx, entry->info.socket_id, entry->info.aid, entry->info.hwid, entry->info.mcatype);
for (i = 0; i < ARRAY_SIZE(reg_idx_array); i++)
seq_printf(m, "mca entry[%d].regs[%d]: 0x%016llx\n", idx, reg_idx_array[i], entry->regs[reg_idx_array[i]]);
}
static int mca_dump_show(struct seq_file *m, enum amdgpu_mca_error_type type)
{
struct amdgpu_device *adev = (struct amdgpu_device *)m->private;
struct mca_bank_node *node;
struct mca_bank_set mca_set;
struct ras_query_context qctx;
int ret;
amdgpu_mca_bank_set_init(&mca_set);
qctx.evid.event_id = RAS_EVENT_INVALID_ID;
ret = amdgpu_mca_smu_get_mca_set(adev, type, &mca_set, &qctx);
if (ret)
goto err_free_mca_set;
seq_printf(m, "amdgpu smu %s valid mca count: %d\n",
type == AMDGPU_MCA_ERROR_TYPE_UE ? "UE" : "CE", mca_set.nr_entries);
if (!mca_set.nr_entries)
goto err_free_mca_set;
list_for_each_entry(node, &mca_set.list, node)
mca_dump_entry(m, &node->entry);
/* add mca bank to mca bank cache */
ret = amdgpu_mca_add_mca_set_to_cache(adev, type, &mca_set);
err_free_mca_set:
amdgpu_mca_bank_set_release(&mca_set);
return ret;
}
static int mca_dump_ce_show(struct seq_file *m, void *unused)
{
return mca_dump_show(m, AMDGPU_MCA_ERROR_TYPE_CE);
}
static int mca_dump_ce_open(struct inode *inode, struct file *file)
{
return single_open(file, mca_dump_ce_show, inode->i_private);
}
static const struct file_operations mca_ce_dump_debug_fops = {
.owner = THIS_MODULE,
.open = mca_dump_ce_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static int mca_dump_ue_show(struct seq_file *m, void *unused)
{
return mca_dump_show(m, AMDGPU_MCA_ERROR_TYPE_UE);
}
static int mca_dump_ue_open(struct inode *inode, struct file *file)
{
return single_open(file, mca_dump_ue_show, inode->i_private);
}
static const struct file_operations mca_ue_dump_debug_fops = {
.owner = THIS_MODULE,
.open = mca_dump_ue_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
DEFINE_DEBUGFS_ATTRIBUTE(mca_debug_mode_fops, NULL, amdgpu_mca_smu_debug_mode_set, "%llu\n");
#endif
void amdgpu_mca_smu_debugfs_init(struct amdgpu_device *adev, struct dentry *root)
{
#if defined(CONFIG_DEBUG_FS)
if (!root)
return;
debugfs_create_file("mca_debug_mode", 0200, root, adev, &mca_debug_mode_fops);
debugfs_create_file("mca_ue_dump", 0400, root, adev, &mca_ue_dump_debug_fops);
debugfs_create_file("mca_ce_dump", 0400, root, adev, &mca_ce_dump_debug_fops);
#endif
}

View File

@@ -23,45 +23,6 @@
#include "amdgpu_ras.h"
#define MCA_MAX_REGS_COUNT (16)
#define MCA_REG_FIELD(x, h, l) (((x) & GENMASK_ULL(h, l)) >> l)
#define MCA_REG__STATUS__VAL(x) MCA_REG_FIELD(x, 63, 63)
#define MCA_REG__STATUS__OVERFLOW(x) MCA_REG_FIELD(x, 62, 62)
#define MCA_REG__STATUS__UC(x) MCA_REG_FIELD(x, 61, 61)
#define MCA_REG__STATUS__EN(x) MCA_REG_FIELD(x, 60, 60)
#define MCA_REG__STATUS__MISCV(x) MCA_REG_FIELD(x, 59, 59)
#define MCA_REG__STATUS__ADDRV(x) MCA_REG_FIELD(x, 58, 58)
#define MCA_REG__STATUS__PCC(x) MCA_REG_FIELD(x, 57, 57)
#define MCA_REG__STATUS__ERRCOREIDVAL(x) MCA_REG_FIELD(x, 56, 56)
#define MCA_REG__STATUS__TCC(x) MCA_REG_FIELD(x, 55, 55)
#define MCA_REG__STATUS__SYNDV(x) MCA_REG_FIELD(x, 53, 53)
#define MCA_REG__STATUS__CECC(x) MCA_REG_FIELD(x, 46, 46)
#define MCA_REG__STATUS__UECC(x) MCA_REG_FIELD(x, 45, 45)
#define MCA_REG__STATUS__DEFERRED(x) MCA_REG_FIELD(x, 44, 44)
#define MCA_REG__STATUS__POISON(x) MCA_REG_FIELD(x, 43, 43)
#define MCA_REG__STATUS__SCRUB(x) MCA_REG_FIELD(x, 40, 40)
#define MCA_REG__STATUS__ERRCOREID(x) MCA_REG_FIELD(x, 37, 32)
#define MCA_REG__STATUS__ADDRLSB(x) MCA_REG_FIELD(x, 29, 24)
#define MCA_REG__STATUS__ERRORCODEEXT(x) MCA_REG_FIELD(x, 21, 16)
#define MCA_REG__STATUS__ERRORCODE(x) MCA_REG_FIELD(x, 15, 0)
#define MCA_REG__MISC0__ERRCNT(x) MCA_REG_FIELD(x, 43, 32)
#define MCA_REG__SYND__ERRORINFORMATION(x) MCA_REG_FIELD(x, 17, 0)
enum amdgpu_mca_ip {
AMDGPU_MCA_IP_UNKNOW = -1,
AMDGPU_MCA_IP_PSP = 0,
AMDGPU_MCA_IP_SDMA,
AMDGPU_MCA_IP_GC,
AMDGPU_MCA_IP_SMU,
AMDGPU_MCA_IP_MP5,
AMDGPU_MCA_IP_UMC,
AMDGPU_MCA_IP_PCS_XGMI,
AMDGPU_MCA_IP_COUNT,
};
enum amdgpu_mca_error_type {
AMDGPU_MCA_ERROR_TYPE_UE = 0,
AMDGPU_MCA_ERROR_TYPE_CE,
@@ -77,77 +38,20 @@ struct amdgpu_mca_ras {
struct amdgpu_mca_ras_block *ras;
};
struct mca_bank_set {
int nr_entries;
struct list_head list;
};
struct mca_bank_cache {
struct mca_bank_set mca_set;
struct mutex lock;
};
struct amdgpu_mca {
struct amdgpu_mca_ras mp0;
struct amdgpu_mca_ras mp1;
struct amdgpu_mca_ras mpio;
const struct amdgpu_mca_smu_funcs *mca_funcs;
struct mca_bank_cache mca_caches[AMDGPU_MCA_ERROR_TYPE_DE];
atomic_t ue_update_flag;
};
enum mca_reg_idx {
MCA_REG_IDX_STATUS = 1,
MCA_REG_IDX_ADDR = 2,
MCA_REG_IDX_MISC0 = 3,
MCA_REG_IDX_IPID = 5,
MCA_REG_IDX_SYND = 6,
MCA_REG_IDX_COUNT = 16,
};
struct mca_bank_info {
int socket_id;
int aid;
int hwid;
int mcatype;
};
struct mca_bank_entry {
int idx;
enum amdgpu_mca_error_type type;
enum amdgpu_mca_ip ip;
struct mca_bank_info info;
uint64_t regs[MCA_MAX_REGS_COUNT];
};
struct mca_bank_node {
struct mca_bank_entry entry;
struct list_head node;
};
struct amdgpu_mca_smu_funcs {
int max_ue_count;
int max_ce_count;
int (*mca_set_debug_mode)(struct amdgpu_device *adev, bool enable);
int (*mca_parse_mca_error_count)(struct amdgpu_device *adev, enum amdgpu_ras_block blk, enum amdgpu_mca_error_type type,
struct mca_bank_entry *entry, uint32_t *count);
int (*mca_get_valid_mca_count)(struct amdgpu_device *adev, enum amdgpu_mca_error_type type,
uint32_t *count);
int (*mca_get_mca_entry)(struct amdgpu_device *adev, enum amdgpu_mca_error_type type,
int idx, struct mca_bank_entry *entry);
};
void amdgpu_mca_query_correctable_error_count(struct amdgpu_device *adev,
uint64_t mc_status_addr,
unsigned long *error_count);
void amdgpu_mca_query_uncorrectable_error_count(struct amdgpu_device *adev,
uint64_t mc_status_addr,
unsigned long *error_count);
void amdgpu_mca_reset_error_count(struct amdgpu_device *adev,
uint64_t mc_status_addr);
void amdgpu_mca_query_ras_error_count(struct amdgpu_device *adev,
uint64_t mc_status_addr,
void *ras_error_status);
@@ -155,15 +59,4 @@ int amdgpu_mca_mp0_ras_sw_init(struct amdgpu_device *adev);
int amdgpu_mca_mp1_ras_sw_init(struct amdgpu_device *adev);
int amdgpu_mca_mpio_ras_sw_init(struct amdgpu_device *adev);
void amdgpu_mca_smu_init_funcs(struct amdgpu_device *adev, const struct amdgpu_mca_smu_funcs *mca_funcs);
int amdgpu_mca_init(struct amdgpu_device *adev);
void amdgpu_mca_fini(struct amdgpu_device *adev);
int amdgpu_mca_reset(struct amdgpu_device *adev);
int amdgpu_mca_smu_set_debug_mode(struct amdgpu_device *adev, bool enable);
int amdgpu_mca_smu_get_mca_set_error_count(struct amdgpu_device *adev, enum amdgpu_ras_block blk,
enum amdgpu_mca_error_type type, uint32_t *total);
void amdgpu_mca_smu_debugfs_init(struct amdgpu_device *adev, struct dentry *root);
int amdgpu_mca_smu_log_ras_error(struct amdgpu_device *adev, enum amdgpu_ras_block blk, enum amdgpu_mca_error_type type,
struct ras_err_data *err_data, struct ras_query_context *qctx);
#endif

View File

@@ -217,7 +217,7 @@ int amdgpu_mes_init(struct amdgpu_device *adev)
if (r)
goto error_doorbell;
if (amdgpu_ip_version(adev, GC_HWIP, 0) >= IP_VERSION(12, 1, 0)) {
if (amdgpu_ip_version(adev, GC_HWIP, 0) >= IP_VERSION(11, 0, 0)) {
/* When queue/pipe reset is done in MES instead of in the
* driver, MES passes hung queues information to the driver in
* hung_queue_hqd_info. Calculate required space to store this
@@ -252,6 +252,10 @@ int amdgpu_mes_init(struct amdgpu_device *adev)
}
}
adev->gfx.mec.mes_hung_db_array =
kcalloc(amdgpu_mes_get_hung_queue_db_array_size(adev),
sizeof(u32), GFP_KERNEL);
return 0;
error_doorbell:
@@ -279,6 +283,8 @@ void amdgpu_mes_fini(struct amdgpu_device *adev)
int i;
int num_xcc = adev->gfx.xcc_mask ? NUM_XCC(adev->gfx.xcc_mask) : 1;
kfree(adev->gfx.mec.mes_hung_db_array);
amdgpu_bo_free_kernel(&adev->mes.event_log_gpu_obj,
&adev->mes.event_log_gpu_addr,
&adev->mes.event_log_cpu_addr);
@@ -439,6 +445,59 @@ int amdgpu_mes_reset_legacy_queue(struct amdgpu_device *adev,
return r;
}
int amdgpu_mes_reset_queue_mmio(struct amdgpu_device *adev,
int queue_type,
unsigned int vmid,
unsigned int me,
unsigned int pipe,
unsigned int queue,
uint32_t xcc_id)
{
struct mes_reset_queue_input queue_input;
int r;
memset(&queue_input, 0, sizeof(queue_input));
queue_input.xcc_id = xcc_id;
queue_input.me_id = me;
queue_input.pipe_id = pipe;
queue_input.queue_id = queue;
queue_input.vmid = vmid;
queue_input.queue_type = queue_type;
queue_input.use_mmio = true;
amdgpu_mes_lock(&adev->mes);
r = adev->mes.funcs->reset_hw_queue(&adev->mes, &queue_input);
amdgpu_mes_unlock(&adev->mes);
if (r)
dev_err(adev->dev, "failed to reset legacy queue\n");
return r;
}
int amdgpu_mes_reset_user_queue(struct amdgpu_device *adev,
int queue_type,
unsigned int doorbell_index,
unsigned int xcc_id)
{
struct mes_reset_queue_input queue_input;
int r;
memset(&queue_input, 0, sizeof(queue_input));
queue_input.xcc_id = xcc_id;
queue_input.queue_type = queue_type;
queue_input.doorbell_offset = doorbell_index;
amdgpu_mes_lock(&adev->mes);
r = adev->mes.funcs->reset_hw_queue(&adev->mes, &queue_input);
amdgpu_mes_unlock(&adev->mes);
if (r)
dev_err(adev->dev, "failed to reset user queue\n");
return r;
}
int amdgpu_mes_get_hung_queue_db_array_size(struct amdgpu_device *adev)
{
return adev->mes.hung_queue_db_array_size;
@@ -805,8 +864,13 @@ bool amdgpu_mes_suspend_resume_all_supported(struct amdgpu_device *adev)
bool amdgpu_mes_queue_reset_by_mes_supported(struct amdgpu_device *adev)
{
return (amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(12, 1, 0) &&
(adev->mes.sched_version & AMDGPU_MES_VERSION_MASK) >= 0x73);
u32 ip_maj = IP_VERSION_MAJ(amdgpu_ip_version(adev, GC_HWIP, 0));
u32 ip_min = IP_VERSION_MIN(amdgpu_ip_version(adev, GC_HWIP, 0));
u32 mes_sched = adev->mes.sched_version & AMDGPU_MES_VERSION_MASK;
return (ip_maj == 11 && mes_sched >= 0x8c) ||
((ip_maj == 12 && ip_min == 0) && mes_sched >= 0x8d) ||
((ip_maj == 12 && ip_min == 1) && mes_sched >= 0x73);
}
/* Fix me -- node_id is used to identify the correct MES instances in the future */

View File

@@ -168,6 +168,9 @@ struct amdgpu_mes {
int master_xcc_ids[AMDGPU_MAX_MES_INST_PIPES];
struct amdgpu_bo *shared_cmd_buf_obj[AMDGPU_MAX_MES_INST_PIPES];
uint64_t shared_cmd_buf_gpu_addr[AMDGPU_MAX_MES_INST_PIPES];
bool compute_pipe_reset_enabled;
bool gfx_pipe_reset_enabled;
};
struct amdgpu_mes_hung_queue_hqd_info {
@@ -271,6 +274,7 @@ struct mes_remove_queue_input {
uint32_t xcc_id;
uint32_t doorbell_offset;
uint64_t gang_context_addr;
uint32_t queue_type;
bool remove_queue_after_reset;
};
@@ -461,6 +465,17 @@ int amdgpu_mes_reset_legacy_queue(struct amdgpu_device *adev,
unsigned int vmid,
bool use_mmio,
uint32_t xcc_id);
int amdgpu_mes_reset_queue_mmio(struct amdgpu_device *adev,
int queue_type,
unsigned int vmid,
unsigned int me,
unsigned int pipe,
unsigned int queue,
uint32_t xcc_id);
int amdgpu_mes_reset_user_queue(struct amdgpu_device *adev,
int queue_type,
unsigned int doorbell_index,
unsigned int xcc_id);
int amdgpu_mes_get_hung_queue_db_array_size(struct amdgpu_device *adev);
int amdgpu_mes_detect_and_reset_hung_queues(struct amdgpu_device *adev,

View File

@@ -21,29 +21,6 @@
#ifndef __AMDGPU_MMHUB_H__
#define __AMDGPU_MMHUB_H__
enum amdgpu_mmhub_ras_memory_id {
AMDGPU_MMHUB_WGMI_PAGEMEM = 0,
AMDGPU_MMHUB_RGMI_PAGEMEM = 1,
AMDGPU_MMHUB_WDRAM_PAGEMEM = 2,
AMDGPU_MMHUB_RDRAM_PAGEMEM = 3,
AMDGPU_MMHUB_WIO_CMDMEM = 4,
AMDGPU_MMHUB_RIO_CMDMEM = 5,
AMDGPU_MMHUB_WGMI_CMDMEM = 6,
AMDGPU_MMHUB_RGMI_CMDMEM = 7,
AMDGPU_MMHUB_WDRAM_CMDMEM = 8,
AMDGPU_MMHUB_RDRAM_CMDMEM = 9,
AMDGPU_MMHUB_MAM_DMEM0 = 10,
AMDGPU_MMHUB_MAM_DMEM1 = 11,
AMDGPU_MMHUB_MAM_DMEM2 = 12,
AMDGPU_MMHUB_MAM_DMEM3 = 13,
AMDGPU_MMHUB_WRET_TAGMEM = 19,
AMDGPU_MMHUB_RRET_TAGMEM = 20,
AMDGPU_MMHUB_WIO_DATAMEM = 21,
AMDGPU_MMHUB_WGMI_DATAMEM = 22,
AMDGPU_MMHUB_WDRAM_DATAMEM = 23,
AMDGPU_MMHUB_MEMORY_BLOCK_LAST,
};
struct amdgpu_mmhub_ras {
struct amdgpu_ras_block_object ras_block;
};

View File

@@ -312,46 +312,6 @@ uint32_t amdgpu_bo_mem_stats_placement(struct amdgpu_bo *bo);
uint32_t amdgpu_bo_get_preferred_domain(struct amdgpu_device *adev,
uint32_t domain);
/*
* sub allocation
*/
static inline struct amdgpu_sa_manager *
to_amdgpu_sa_manager(struct drm_suballoc_manager *manager)
{
return container_of(manager, struct amdgpu_sa_manager, base);
}
static inline uint64_t amdgpu_sa_bo_gpu_addr(struct drm_suballoc *sa_bo)
{
return to_amdgpu_sa_manager(sa_bo->manager)->gpu_addr +
drm_suballoc_soffset(sa_bo);
}
static inline void *amdgpu_sa_bo_cpu_addr(struct drm_suballoc *sa_bo)
{
return to_amdgpu_sa_manager(sa_bo->manager)->cpu_ptr +
drm_suballoc_soffset(sa_bo);
}
int amdgpu_sa_bo_manager_init(struct amdgpu_device *adev,
struct amdgpu_sa_manager *sa_manager,
unsigned size, u32 align, u32 domain);
void amdgpu_sa_bo_manager_fini(struct amdgpu_device *adev,
struct amdgpu_sa_manager *sa_manager);
int amdgpu_sa_bo_manager_start(struct amdgpu_device *adev,
struct amdgpu_sa_manager *sa_manager);
int amdgpu_sa_bo_new(struct amdgpu_sa_manager *sa_manager,
struct drm_suballoc **sa_bo,
unsigned int size);
void amdgpu_sa_bo_free(struct drm_suballoc **sa_bo,
struct dma_fence *fence);
#if defined(CONFIG_DEBUG_FS)
void amdgpu_sa_bo_dump_debug_info(struct amdgpu_sa_manager *sa_manager,
struct seq_file *m);
u64 amdgpu_bo_print_info(int id, struct amdgpu_bo *bo, struct seq_file *m);
#endif
void amdgpu_debugfs_sa_init(struct amdgpu_device *adev);
bool amdgpu_bo_support_uswc(u64 bo_flags);

View File

@@ -46,6 +46,17 @@ static ssize_t mem_info_preempt_used_show(struct device *dev,
static DEVICE_ATTR_RO(mem_info_preempt_used);
/**
* amdgpu_preempt_mgr_sysfs_fini - remove PREEMPT manager sysfs attributes
*
* @adev: amdgpu_device pointer
*/
void amdgpu_preempt_mgr_sysfs_fini(struct amdgpu_device *adev)
{
if (adev->dev->kobj.sd)
device_remove_file(adev->dev, &dev_attr_mem_info_preempt_used);
}
/**
* amdgpu_preempt_mgr_new - allocate a new node
*
@@ -137,9 +148,6 @@ void amdgpu_preempt_mgr_fini(struct amdgpu_device *adev)
if (ret)
return;
if (adev->dev->kobj.sd)
device_remove_file(adev->dev, &dev_attr_mem_info_preempt_used);
ttm_resource_manager_cleanup(man);
ttm_set_driver_manager(&adev->mman.bdev, AMDGPU_PL_PREEMPT, NULL);
}

View File

@@ -166,7 +166,8 @@ static ssize_t ta_if_load_debugfs_write(struct file *fp, const char *buf, size_t
if (ret)
return -EFAULT;
if (ta_bin_len > PSP_1_MEG)
if (ta_bin_len < sizeof(struct common_firmware_header) ||
ta_bin_len > PSP_1_MEG)
return -EINVAL;
copy_pos += sizeof(uint32_t);
@@ -321,6 +322,8 @@ static ssize_t ta_if_invoke_debugfs_write(struct file *fp, const char *buf, size
ret = copy_from_user((void *)&shared_buf_len, &buf[copy_pos], sizeof(uint32_t));
if (ret)
return -EFAULT;
if (!shared_buf_len || shared_buf_len > PSP_1_MEG)
return -EINVAL;
copy_pos += sizeof(uint32_t);
shared_buf = memdup_user(&buf[copy_pos], shared_buf_len);

File diff suppressed because it is too large Load Diff

View File

@@ -31,7 +31,6 @@
#include "ta_ras_if.h"
#include "amdgpu_ras_eeprom.h"
#include "amdgpu_smuio.h"
#include "amdgpu_aca.h"
struct amdgpu_iv_entry;
@@ -466,14 +465,6 @@ struct ras_query_context {
typedef int (*pasid_notify)(struct amdgpu_device *adev,
uint16_t pasid, void *data);
struct ras_poison_msg {
enum amdgpu_ras_block block;
uint16_t pasid;
uint32_t reset;
pasid_notify pasid_fn;
void *data;
};
struct ras_err_pages {
uint32_t count;
uint64_t *pfn;
@@ -492,8 +483,6 @@ struct ras_ecc_err {
struct ras_ecc_log_info {
struct mutex lock;
struct radix_tree_root de_page_tree;
uint64_t de_queried_count;
uint64_t consumption_q_count;
};
struct ras_critical_region {
@@ -549,7 +538,6 @@ struct amdgpu_ras {
/* gpu recovery */
struct work_struct recovery_work;
atomic_t in_recovery;
atomic_t rma_in_recovery;
struct amdgpu_device *adev;
/* error handler data */
struct ras_err_handler_data *eh_data;
@@ -581,22 +569,15 @@ struct amdgpu_ras {
/* Indicates smu whether need update bad channel info */
bool update_channel_flag;
/* Record status of smu mca debug mode */
bool is_aca_debug_mode;
bool is_mca_debug_mode;
bool is_rma;
/* Record special requirements of gpu reset caller */
uint32_t gpu_reset_flags;
struct task_struct *page_retirement_thread;
wait_queue_head_t page_retirement_wq;
struct mutex page_retirement_lock;
atomic_t page_retirement_req_cnt;
atomic_t poison_creation_count;
atomic_t poison_consumption_count;
struct mutex page_rsv_lock;
DECLARE_KFIFO(poison_fifo, struct ras_poison_msg, 128);
struct ras_ecc_log_info umc_ecc_log;
struct delayed_work page_retirement_dwork;
/* ras errors detected */
unsigned long ras_err_state;
@@ -615,9 +596,6 @@ struct amdgpu_ras {
struct list_head critical_region_head;
struct mutex critical_region_lock;
/* Protect poison injection */
struct mutex poison_lock;
/* Disable/Enable uniras switch */
bool uniras_enabled;
const struct ras_smu_drv *ras_smu_drv;
@@ -702,8 +680,6 @@ struct ras_manager {
struct ras_ih_data ih_data;
struct ras_err_data err_data;
struct aca_handle aca_handle;
};
struct ras_badpage {
@@ -964,8 +940,7 @@ struct amdgpu_ras* amdgpu_ras_get_context(struct amdgpu_device *adev);
int amdgpu_ras_set_context(struct amdgpu_device *adev, struct amdgpu_ras *ras_con);
int amdgpu_ras_set_mca_debug_mode(struct amdgpu_device *adev, bool enable);
int amdgpu_ras_set_aca_debug_mode(struct amdgpu_device *adev, bool enable);
bool amdgpu_ras_get_aca_debug_mode(struct amdgpu_device *adev);
bool amdgpu_ras_get_mca_debug_mode(struct amdgpu_device *adev);
bool amdgpu_ras_get_error_query_mode(struct amdgpu_device *adev,
unsigned int *mode);
@@ -1006,12 +981,6 @@ int amdgpu_ras_error_statistic_de_count(struct ras_err_data *err_data,
struct amdgpu_smuio_mcm_config_info *mcm_info,
u64 count);
void amdgpu_ras_query_boot_status(struct amdgpu_device *adev, u32 num_instances);
int amdgpu_ras_bind_aca(struct amdgpu_device *adev, enum amdgpu_ras_block blk,
const struct aca_info *aca_info, void *data);
int amdgpu_ras_unbind_aca(struct amdgpu_device *adev, enum amdgpu_ras_block blk);
ssize_t amdgpu_ras_aca_sysfs_read(struct device *dev, struct device_attribute *attr,
struct aca_handle *handle, char *buf, void *data);
void amdgpu_ras_set_fed(struct amdgpu_device *adev, bool status);
bool amdgpu_ras_get_fed_status(struct amdgpu_device *adev);
@@ -1029,10 +998,6 @@ int amdgpu_ras_reserve_page(struct amdgpu_device *adev, uint64_t pfn);
int amdgpu_ras_add_critical_region(struct amdgpu_device *adev, struct amdgpu_bo *bo);
bool amdgpu_ras_check_critical_address(struct amdgpu_device *adev, uint64_t addr);
int amdgpu_ras_put_poison_req(struct amdgpu_device *adev,
enum amdgpu_ras_block block, uint16_t pasid,
pasid_notify pasid_fn, void *data, uint32_t reset);
bool amdgpu_ras_in_recovery(struct amdgpu_device *adev);
__printf(3, 4)
@@ -1045,4 +1010,5 @@ void amdgpu_ras_pre_reset(struct amdgpu_device *adev,
struct list_head *device_list);
void amdgpu_ras_post_reset(struct amdgpu_device *adev,
struct list_head *device_list);
void amdgpu_ras_resume_after_reset(struct amdgpu_device *adev);
#endif

View File

@@ -124,8 +124,6 @@
RAS_TABLE_V2_1_INFO_SIZE) \
/ RAS_TABLE_RECORD_SIZE)
#define RAS_SMU_MESSAGE_TIMEOUT_MS 1000 /* 1s */
/* Given a zero-based index of an EEPROM RAS record, yields the EEPROM
* offset off of RAS_TABLE_START. That is, this is something you can
* add to control->i2c_address, and then tell I2C layer to read
@@ -159,6 +157,9 @@
static bool __is_ras_eeprom_supported(struct amdgpu_device *adev)
{
if (amdgpu_sriov_vf(adev))
return false;
switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) {
case IP_VERSION(11, 0, 2): /* VEGA20 and ARCTURUS */
case IP_VERSION(11, 0, 7): /* Sienna cichlid */
@@ -449,57 +450,46 @@ int amdgpu_ras_eeprom_reset_table(struct amdgpu_ras_eeprom_control *control)
struct amdgpu_ras_eeprom_table_header *hdr = &control->tbl_hdr;
struct amdgpu_ras_eeprom_table_ras_info *rai = &control->tbl_rai;
struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
u32 erase_res = 0;
u8 csum;
int res;
mutex_lock(&control->ras_tbl_mutex);
if (!amdgpu_ras_smu_eeprom_supported(adev)) {
hdr->header = RAS_TABLE_HDR_VAL;
amdgpu_ras_set_eeprom_table_version(control);
hdr->header = RAS_TABLE_HDR_VAL;
amdgpu_ras_set_eeprom_table_version(control);
if (hdr->version >= RAS_TABLE_VER_V2_1) {
hdr->first_rec_offset = RAS_RECORD_START_V2_1;
hdr->tbl_size = RAS_TABLE_HEADER_SIZE +
RAS_TABLE_V2_1_INFO_SIZE;
rai->rma_status = GPU_HEALTH_USABLE;
if (hdr->version >= RAS_TABLE_VER_V2_1) {
hdr->first_rec_offset = RAS_RECORD_START_V2_1;
hdr->tbl_size = RAS_TABLE_HEADER_SIZE +
RAS_TABLE_V2_1_INFO_SIZE;
rai->rma_status = GPU_HEALTH_USABLE;
control->ras_record_offset = RAS_RECORD_START_V2_1;
control->ras_max_record_count = RAS_MAX_RECORD_COUNT_V2_1;
/**
* GPU health represented as a percentage.
* 0 means worst health, 100 means fully health.
*/
rai->health_percent = 100;
/* ecc_page_threshold = 0 means disable bad page retirement */
rai->ecc_page_threshold = con->bad_page_cnt_threshold;
} else {
hdr->first_rec_offset = RAS_RECORD_START;
hdr->tbl_size = RAS_TABLE_HEADER_SIZE;
control->ras_record_offset = RAS_RECORD_START;
control->ras_max_record_count = RAS_MAX_RECORD_COUNT;
}
csum = __calc_hdr_byte_sum(control);
if (hdr->version >= RAS_TABLE_VER_V2_1)
csum += __calc_ras_info_byte_sum(control);
csum = -csum;
hdr->checksum = csum;
res = __write_table_header(control);
if (!res && hdr->version > RAS_TABLE_VER_V1)
res = __write_table_ras_info(control);
control->ras_record_offset = RAS_RECORD_START_V2_1;
control->ras_max_record_count = RAS_MAX_RECORD_COUNT_V2_1;
/**
* GPU health represented as a percentage.
* 0 means worst health, 100 means fully health.
*/
rai->health_percent = 100;
/* ecc_page_threshold = 0 means disable bad page retirement */
rai->ecc_page_threshold = con->bad_page_cnt_threshold;
} else {
res = amdgpu_ras_smu_erase_ras_table(adev, &erase_res);
if (res || erase_res) {
dev_warn(adev->dev, "RAS EEPROM reset failed, res:%d result:%d",
res, erase_res);
if (!res)
res = -EIO;
}
hdr->first_rec_offset = RAS_RECORD_START;
hdr->tbl_size = RAS_TABLE_HEADER_SIZE;
control->ras_record_offset = RAS_RECORD_START;
control->ras_max_record_count = RAS_MAX_RECORD_COUNT;
}
csum = __calc_hdr_byte_sum(control);
if (hdr->version >= RAS_TABLE_VER_V2_1)
csum += __calc_ras_info_byte_sum(control);
csum = -csum;
hdr->checksum = csum;
res = __write_table_header(control);
if (!res && hdr->version > RAS_TABLE_VER_V1)
res = __write_table_ras_info(control);
control->ras_num_recs = 0;
control->ras_num_bad_pages = 0;
control->ras_num_mca_recs = 0;
@@ -662,7 +652,6 @@ amdgpu_ras_eeprom_append_table(struct amdgpu_ras_eeprom_control *control,
const u32 num)
{
struct amdgpu_ras *con = amdgpu_ras_get_context(to_amdgpu_device(control));
struct amdgpu_device *adev = to_amdgpu_device(control);
u32 a, b, i;
u8 *buf, *pp;
int res;
@@ -767,10 +756,7 @@ amdgpu_ras_eeprom_append_table(struct amdgpu_ras_eeprom_control *control,
% control->ras_max_record_count;
/*old asics only save pa to eeprom like before*/
if (IP_VERSION_MAJ(amdgpu_ip_version(adev, UMC_HWIP, 0)) < 12)
control->ras_num_pa_recs += num;
else
control->ras_num_mca_recs += num;
control->ras_num_pa_recs += num;
control->ras_num_bad_pages = con->bad_page_num;
Out:
@@ -879,71 +865,6 @@ amdgpu_ras_eeprom_update_header(struct amdgpu_ras_eeprom_control *control)
return res;
}
int amdgpu_ras_eeprom_update_record_num(struct amdgpu_ras_eeprom_control *control)
{
struct amdgpu_device *adev = to_amdgpu_device(control);
int ret, retry = 20;
if (!amdgpu_ras_smu_eeprom_supported(adev))
return 0;
control->ras_num_recs_old = control->ras_num_recs;
do {
/* 1000ms timeout is long enough, smu_get_badpage_count won't
* return -EBUSY before timeout.
*/
ret = amdgpu_ras_smu_get_badpage_count(adev,
&(control->ras_num_recs), RAS_SMU_MESSAGE_TIMEOUT_MS);
if (!ret &&
(control->ras_num_recs_old == control->ras_num_recs)) {
/* record number update in PMFW needs some time,
* smu_get_badpage_count may return immediately without
* count update, sleep for a while and retry again.
*/
msleep(50);
retry--;
} else {
break;
}
} while (retry);
/* no update of record number is not a real failure,
* don't print warning here
*/
if (!ret && (control->ras_num_recs_old == control->ras_num_recs))
ret = -EINVAL;
return ret;
}
static int amdgpu_ras_smu_eeprom_append(struct amdgpu_ras_eeprom_control *control)
{
struct amdgpu_device *adev = to_amdgpu_device(control);
struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
if (!amdgpu_ras_smu_eeprom_supported(adev) || !con)
return 0;
control->ras_num_bad_pages = con->bad_page_num;
if (amdgpu_bad_page_threshold != 0 &&
control->ras_num_bad_pages > con->bad_page_cnt_threshold) {
dev_warn(adev->dev,
"Saved bad pages %d reaches threshold value %d\n",
control->ras_num_bad_pages, con->bad_page_cnt_threshold);
if (adev->cper.enabled && amdgpu_cper_generate_bp_threshold_record(adev))
dev_warn(adev->dev, "fail to generate bad page threshold cper records\n");
if ((amdgpu_bad_page_threshold != -1) &&
(amdgpu_bad_page_threshold != -2))
con->is_rma = true;
}
return 0;
}
/**
* amdgpu_ras_eeprom_append -- append records to the EEPROM RAS table
* @control: pointer to control structure
@@ -968,9 +889,6 @@ int amdgpu_ras_eeprom_append(struct amdgpu_ras_eeprom_control *control,
if (!__is_ras_eeprom_supported(adev))
return 0;
if (amdgpu_ras_smu_eeprom_supported(adev))
return amdgpu_ras_smu_eeprom_append(control);
if (num == 0) {
dev_err(adev->dev, "will not append 0 records\n");
return -EINVAL;
@@ -1046,52 +964,6 @@ static int __amdgpu_ras_eeprom_read(struct amdgpu_ras_eeprom_control *control,
return res;
}
int amdgpu_ras_eeprom_read_idx(struct amdgpu_ras_eeprom_control *control,
struct eeprom_table_record *record, u32 rec_idx,
const u32 num)
{
struct amdgpu_device *adev = to_amdgpu_device(control);
uint64_t ts, end_idx;
int i, ret;
u64 mca, ipid;
u32 cu, mem_channel, mcumc_id;
if (!amdgpu_ras_smu_eeprom_supported(adev))
return 0;
if (!adev->umc.ras || !adev->umc.ras->mca_ipid_parse)
return -EOPNOTSUPP;
end_idx = rec_idx + num;
for (i = rec_idx; i < end_idx; i++) {
ret = amdgpu_ras_smu_get_badpage_mca_addr(adev, i, &mca);
if (ret)
return ret;
ret = amdgpu_ras_smu_get_badpage_ipid(adev, i, &ipid);
if (ret)
return ret;
ret = amdgpu_ras_smu_get_timestamp(adev, i, &ts);
if (ret)
return ret;
record[i - rec_idx].address = mca;
/* retired_page (pa) is unused now */
record[i - rec_idx].retired_page = 0x1ULL;
record[i - rec_idx].ts = ts;
record[i - rec_idx].err_type = AMDGPU_RAS_EEPROM_ERR_NON_RECOVERABLE;
adev->umc.ras->mca_ipid_parse(adev, ipid,
&cu, &mem_channel, &mcumc_id, NULL);
record[i - rec_idx].cu = (u8)cu;
record[i - rec_idx].mem_channel = (u8)mem_channel;
record[i - rec_idx].mcumc_id = (u8)mcumc_id;
}
return 0;
}
/**
* amdgpu_ras_eeprom_read -- read EEPROM
* @control: pointer to control structure
@@ -1113,9 +985,6 @@ int amdgpu_ras_eeprom_read(struct amdgpu_ras_eeprom_control *control,
u8 *buf, *pp;
u32 g0, g1;
if (amdgpu_ras_smu_eeprom_supported(adev))
return amdgpu_ras_eeprom_read_idx(control, record, 0, num);
if (!__is_ras_eeprom_supported(adev))
return 0;
@@ -1395,6 +1264,86 @@ static ssize_t amdgpu_ras_debugfs_table_read(struct file *f, char __user *buf,
return res < 0 ? res : orig_size - size;
}
static ssize_t
amdgpu_ras_debugfs_table_read_uniras(struct amdgpu_device *adev,
char __user *buf,
size_t size, loff_t *pos)
{
struct amdgpu_ras_mgr *ras_mgr = amdgpu_ras_mgr_get_context(adev);
struct ras_core_context *ras_core = ras_mgr ? ras_mgr->ras_core : NULL;
struct eeprom_umc_record *records = NULL;
struct ras_eeprom_control *control;
size_t bufsz, len = 0;
u32 num_recs;
char *kbuf;
ssize_t res;
int i;
if (!ras_core)
return 0;
/* pmfw manages eeprom data by itself */
if (ras_fw_eeprom_supported(ras_core))
return 0;
control = &ras_core->ras_eeprom;
num_recs = ras_eeprom_get_record_count(ras_core);
bufsz = strlen(tbl_hdr_str) + tbl_hdr_fmt_size +
strlen(rec_hdr_str) + (size_t)rec_hdr_fmt_size * num_recs + 1;
kbuf = kvmalloc(bufsz, GFP_KERNEL);
if (!kbuf)
return -ENOMEM;
if (num_recs) {
records = kvcalloc(num_recs, sizeof(*records), GFP_KERNEL);
if (!records) {
res = -ENOMEM;
goto out;
}
res = ras_eeprom_read(ras_core, records, num_recs);
if (res)
goto out;
}
len += scnprintf(kbuf + len, bufsz - len, "%s", tbl_hdr_str);
len += scnprintf(kbuf + len, bufsz - len, tbl_hdr_fmt,
control->tbl_hdr.header,
control->tbl_hdr.version,
control->tbl_hdr.first_rec_offset,
control->tbl_hdr.tbl_size,
control->tbl_hdr.checksum);
len += scnprintf(kbuf + len, bufsz - len, "%s", rec_hdr_str);
for (i = 0; i < num_recs; i++) {
u32 ai = RAS_RI_TO_AI(control, i);
int et = records[i].err_type;
const char *ets = (et >= 0 && et < AMDGPU_RAS_EEPROM_ERR_COUNT) ?
record_err_type_str[et] : "na";
len += scnprintf(kbuf + len, bufsz - len, rec_hdr_fmt,
i,
RAS_INDEX_TO_OFFSET(control, ai),
ets,
records[i].bank,
records[i].ts,
records[i].offset,
records[i].mem_channel,
records[i].mcumc_id,
records[i].retired_row_pfn);
}
res = simple_read_from_buffer(buf, size, pos, kbuf, len);
out:
kvfree(records);
kvfree(kbuf);
return res;
}
static ssize_t
amdgpu_ras_debugfs_eeprom_table_read(struct file *f, char __user *buf,
size_t size, loff_t *pos)
@@ -1408,6 +1357,10 @@ amdgpu_ras_debugfs_eeprom_table_read(struct file *f, char __user *buf,
if (!size)
return size;
if (amdgpu_uniras_enabled(adev))
return amdgpu_ras_debugfs_table_read_uniras(adev, buf,
size, pos);
if (!ras || !control) {
res = snprintf(data, sizeof(data), "Not supported\n");
if (*pos >= res)
@@ -1521,42 +1474,6 @@ static int __read_table_ras_info(struct amdgpu_ras_eeprom_control *control)
return res == RAS_TABLE_V2_1_INFO_SIZE ? 0 : res;
}
static int amdgpu_ras_smu_eeprom_init(struct amdgpu_ras_eeprom_control *control)
{
struct amdgpu_device *adev = to_amdgpu_device(control);
struct amdgpu_ras_eeprom_table_header *hdr = &control->tbl_hdr;
struct amdgpu_ras *ras = amdgpu_ras_get_context(adev);
uint64_t local_time;
int res;
ras->is_rma = false;
if (!__is_ras_eeprom_supported(adev))
return 0;
mutex_init(&control->ras_tbl_mutex);
res = amdgpu_ras_smu_get_table_version(adev, &(hdr->version));
if (res)
return res;
res = amdgpu_ras_smu_get_badpage_count(adev,
&(control->ras_num_recs), 100);
if (res)
return res;
local_time = (uint64_t)ktime_get_real_seconds();
res = amdgpu_ras_smu_set_timestamp(adev, local_time);
if (res)
return res;
control->ras_max_record_count = 4000;
control->ras_num_mca_recs = 0;
control->ras_num_pa_recs = 0;
return 0;
}
int amdgpu_ras_eeprom_init(struct amdgpu_ras_eeprom_control *control)
{
struct amdgpu_device *adev = to_amdgpu_device(control);
@@ -1567,9 +1484,6 @@ int amdgpu_ras_eeprom_init(struct amdgpu_ras_eeprom_control *control)
uint32_t vram_type = adev->gmc.vram_type;
int res;
if (amdgpu_ras_smu_eeprom_supported(adev))
return amdgpu_ras_smu_eeprom_init(control);
ras->is_rma = false;
if (!__is_ras_eeprom_supported(adev))
@@ -1663,47 +1577,6 @@ int amdgpu_ras_eeprom_init(struct amdgpu_ras_eeprom_control *control)
return 0;
}
static int amdgpu_ras_smu_eeprom_check(struct amdgpu_ras_eeprom_control *control)
{
struct amdgpu_device *adev = to_amdgpu_device(control);
struct amdgpu_ras *ras = amdgpu_ras_get_context(adev);
if (!__is_ras_eeprom_supported(adev))
return 0;
control->ras_num_bad_pages = ras->bad_page_num;
if ((ras->bad_page_cnt_threshold < control->ras_num_bad_pages) &&
amdgpu_bad_page_threshold != 0) {
dev_warn(adev->dev,
"RAS records:%d exceed threshold:%d\n",
control->ras_num_bad_pages, ras->bad_page_cnt_threshold);
if ((amdgpu_bad_page_threshold == -1) ||
(amdgpu_bad_page_threshold == -2)) {
dev_warn(adev->dev,
"Please consult AMD Service Action Guide (SAG) for appropriate service procedures\n");
} else {
ras->is_rma = true;
dev_warn(adev->dev,
"User defined threshold is set, runtime service will be halt when threshold is reached\n");
}
return 0;
}
dev_dbg(adev->dev,
"Found existing EEPROM table with %d records",
control->ras_num_bad_pages);
/* Warn if we are at 90% of the threshold or above
*/
if (10 * control->ras_num_bad_pages >= 9 * ras->bad_page_cnt_threshold)
dev_warn(adev->dev, "RAS records:%u exceeds 90%% of threshold:%d",
control->ras_num_bad_pages,
ras->bad_page_cnt_threshold);
return 0;
}
int amdgpu_ras_eeprom_check(struct amdgpu_ras_eeprom_control *control)
{
struct amdgpu_device *adev = to_amdgpu_device(control);
@@ -1711,9 +1584,6 @@ int amdgpu_ras_eeprom_check(struct amdgpu_ras_eeprom_control *control)
struct amdgpu_ras *ras = amdgpu_ras_get_context(adev);
int res = 0;
if (amdgpu_ras_smu_eeprom_supported(adev))
return amdgpu_ras_smu_eeprom_check(control);
if (!__is_ras_eeprom_supported(adev))
return 0;
@@ -1973,7 +1843,7 @@ void amdgpu_ras_check_bad_page_status(struct amdgpu_device *adev)
struct amdgpu_ras *ras = amdgpu_ras_get_context(adev);
struct amdgpu_ras_eeprom_control *control = ras ? &ras->eeprom_control : NULL;
if (!control || amdgpu_bad_page_threshold == 0)
if (!__is_ras_eeprom_supported(adev) || !control || amdgpu_bad_page_threshold == 0)
return;
if (control->ras_num_bad_pages > ras->bad_page_cnt_threshold) {

View File

@@ -82,7 +82,6 @@ struct amdgpu_ras_eeprom_control {
/* Number of records in the table.
*/
u32 ras_num_recs;
u32 ras_num_recs_old;
/* the bad page number is ras_num_recs or
* ras_num_recs * umc.retire_unit
@@ -191,8 +190,6 @@ int amdgpu_ras_eeprom_read_idx(struct amdgpu_ras_eeprom_control *control,
struct eeprom_table_record *record, u32 rec_idx,
const u32 num);
int amdgpu_ras_eeprom_update_record_num(struct amdgpu_ras_eeprom_control *control);
void amdgpu_ras_check_bad_page_status(struct amdgpu_device *adev);
extern const struct file_operations amdgpu_ras_debugfs_eeprom_size_ops;

View File

@@ -935,6 +935,194 @@ int amdgpu_ring_reset_helper_end(struct amdgpu_ring *ring,
return 0;
}
/**
* amdgpu_multi_ring_reset_helper_begin() - Prepare multiple rings for a reset.
*
* @ring_type_mask: Bitmask of affected ring types
* @guilty_ring: The ring which is guilty of causing a reset.
* @guilty_fence: The fence which didn't signal on the guilty ring.
*
* Useful when performing a GPU reset method that affects
* multiple rings at the same time, such as an IP block soft
* reset. For example, a GFX IP block soft reset will affect
* every graphics and compute queue.
*
* This function should be called before such a reset.
*
* Prepare the affected rings before the reset, make sure to
* minimize collateral damage, and backup the contents of
* the rings. Then the caller can call the actual HW specific
* reset function.
*
* After the reset is complete, the caller should then call
* amdgpu_multi_ring_reset_helper_end() to restore the rings.
*/
void amdgpu_multi_ring_reset_helper_begin(const u32 ring_type_mask,
struct amdgpu_ring *guilty_ring,
struct amdgpu_fence *guilty_fence)
{
struct amdgpu_device *adev = guilty_ring->adev;
struct amdgpu_fence *ring_guilty_fence;
struct amdgpu_ring *ring;
bool rings_busy;
int i;
u32 t;
for (i = 0; i < adev->num_rings; ++i) {
ring = adev->rings[i];
if (!(BIT(ring->funcs->type) & ring_type_mask))
continue;
/* Don't accept new submissions on the ring. */
if (amdgpu_ring_sched_ready(ring) && !drm_sched_is_stopped(&ring->sched))
drm_sched_wqueue_stop(&ring->sched);
/*
* Clear the preempt condition to stop the ring
* from starting its next submission. This ensures
* that only the currently executing submission
* can be rejected because of the reset and helps
* minimize collateral damage.
*/
if (ring->funcs->init_cond_exec)
amdgpu_ring_set_preempt_cond_exec(ring, false);
}
/* Flush HDP cache so the GPU can see the updated COND_EXEC values */
amdgpu_device_flush_hdp(adev, NULL);
/*
* Give some time for non-guilty rings to finish their
* current submission, to try to minimize collateral damage.
*
* Note that this is just a best effort, but really there
* is no way to really know which ring is actually responsible
* because different rings may share resources, eg. a compute
* ring may hog shader engines, causing a graphics ring to hang.
*/
for (t = 0; t < adev->usec_timeout; t += 10000) {
rings_busy = false;
/* Check if any of the non-guilty rings are busy */
for (i = 0; i < adev->num_rings; ++i) {
ring = adev->rings[i];
if (!(BIT(ring->funcs->type) & ring_type_mask))
continue;
if (ring == guilty_ring)
continue;
rings_busy |=
atomic_read(&ring->fence_drv.last_seq) !=
READ_ONCE(ring->fence_drv.sync_seq);
}
if (!rings_busy)
break;
mdelay(10);
}
for (i = 0; i < adev->num_rings; ++i) {
ring = adev->rings[i];
if (!(BIT(ring->funcs->type) & ring_type_mask))
continue;
/*
* Find guilty fences, ie. the fences that didn't signal
* on each ring. At this point there is no way to know
* which one is really responsible for the hang, and no
* way to save any of them, so we treat all of them as guilty.
*/
ring_guilty_fence =
ring == guilty_ring ? guilty_fence :
amdgpu_ring_find_guilty_fence(ring);
/*
* Backup current contents of the ring.
* The helper takes care to only reemit unsignalled fences
* so we don't have to worry about that here.
*/
amdgpu_ring_reset_helper_begin(ring, ring_guilty_fence);
}
}
/**
* amdgpu_multi_ring_reset_helper_end() - Prepare multiple rings for a reset.
*
* @ring_type_mask: Bitmask of affected ring types
* @guilty_ring: The ring which is guilty of causing a reset.
* @ret: Return code from the reset function.
*
* After calling amdgpu_multi_ring_reset_helper_begin()
* and executing the actual reset method, call this
* function to restore normal operation.
*
* In case the reset failed, this function should still
* be called to restore preemption state, but it won't attempt to
* fully restore the ring contents.
*/
int amdgpu_multi_ring_reset_helper_end(const u32 ring_type_mask,
struct amdgpu_ring *guilty_ring, int ret)
{
struct amdgpu_device *adev = guilty_ring->adev;
struct amdgpu_ring *ring;
int i, r;
/* Set preempt condition, rings are now allowed to execute submissions */
for (i = 0; i < adev->num_rings; ++i) {
ring = adev->rings[i];
if (!(BIT(ring->funcs->type) & ring_type_mask))
continue;
if (ring->funcs->init_cond_exec)
amdgpu_ring_set_preempt_cond_exec(ring, true);
}
/* Flush HDP cache so the GPU can see the updated COND_EXEC values */
amdgpu_device_flush_hdp(adev, NULL);
/* If the reset was unsuccessful, return without restoring anything else. */
if (ret)
return ret;
/* Restore contents of all rings */
for (i = 0; i < adev->num_rings; ++i) {
ring = adev->rings[i];
if (!(BIT(ring->funcs->type) & ring_type_mask))
continue;
/* Restore contents of the ring */
r = amdgpu_ring_reset_helper_end(ring, ring->guilty_fence);
if (r) {
dev_err(adev->dev,
"Failed to recover ring %s after soft reset\n",
ring->name);
return r;
}
}
/* Accept submissions on all rings again */
for (i = 0; i < adev->num_rings; ++i) {
ring = adev->rings[i];
if (!(BIT(ring->funcs->type) & ring_type_mask))
continue;
if (!amdgpu_ring_sched_ready(ring))
continue;
drm_sched_wqueue_start(&ring->sched);
}
return 0;
}
bool amdgpu_ring_is_reset_type_supported(struct amdgpu_ring *ring,
u32 reset_type)
{

View File

@@ -314,6 +314,7 @@ struct amdgpu_ring {
uint32_t *ring_backup;
unsigned int ring_backup_entries_to_copy;
bool reemit;
struct amdgpu_fence *guilty_fence;
unsigned rptr_offs;
u64 rptr_gpu_addr;
u32 *rptr_cpu_addr;
@@ -588,10 +589,17 @@ int amdgpu_ib_ring_tests(struct amdgpu_device *adev);
bool amdgpu_ring_sched_ready(struct amdgpu_ring *ring);
void amdgpu_ring_backup_unprocessed_commands(struct amdgpu_ring *ring,
struct amdgpu_fence *guilty_fence);
struct amdgpu_fence *
amdgpu_ring_find_guilty_fence(struct amdgpu_ring *ring);
void amdgpu_ring_reset_helper_begin(struct amdgpu_ring *ring,
struct amdgpu_fence *guilty_fence);
int amdgpu_ring_reset_helper_end(struct amdgpu_ring *ring,
struct amdgpu_fence *guilty_fence);
void amdgpu_multi_ring_reset_helper_begin(const u32 ring_type_mask,
struct amdgpu_ring *guilty_ring,
struct amdgpu_fence *guilty_fence);
int amdgpu_multi_ring_reset_helper_end(const u32 ring_type_mask,
struct amdgpu_ring *guilty_ring, int ret);
bool amdgpu_ring_is_reset_type_supported(struct amdgpu_ring *ring,
u32 reset_type);
#endif

View File

@@ -583,3 +583,42 @@ int amdgpu_gfx_rlc_init_microcode(struct amdgpu_device *adev,
amdgpu_gfx_rlc_init_microcode_v2_5(adev);
return 0;
}
static const struct amdgpu_rlc_reg_funcs amdgpu_sriov_rlc_reg_funcs = {
.rreg32 = amdgpu_sriov_rreg,
.wreg32 = amdgpu_sriov_wreg,
};
static u32
amdgpu_rlc_rreg(struct amdgpu_device *adev, u32 reg, u32 acc_flags, u32 hwip,
u32 xcc_id)
{
return amdgpu_device_rreg(adev, reg, 0);
}
static void
amdgpu_rlc_wreg(struct amdgpu_device *adev, u32 reg, u32 value, u32 acc_flags,
u32 hwip, u32 xcc_id)
{
amdgpu_device_wreg(adev, reg, value, 0);
}
static const struct amdgpu_rlc_reg_funcs amdgpu_rlc_reg_funcs = {
.rreg32 = amdgpu_rlc_rreg,
.wreg32 = amdgpu_rlc_wreg,
};
void amdgpu_early_init_rlc_reg_funcs(struct amdgpu_device *adev)
{
adev->gfx.rlc.reg_funcs = &amdgpu_rlc_reg_funcs;
}
void amdgpu_init_rlc_reg_funcs(struct amdgpu_device *adev)
{
if (amdgpu_sriov_vf(adev) &&
adev->gfx.rlc.funcs &&
adev->gfx.rlc.rlcg_reg_access_supported)
adev->gfx.rlc.reg_funcs = &amdgpu_sriov_rlc_reg_funcs;
else
adev->gfx.rlc.reg_funcs = &amdgpu_rlc_reg_funcs;
}

View File

@@ -262,6 +262,11 @@ struct amdgpu_rlc_funcs {
bool (*is_rlcg_access_range)(struct amdgpu_device *adev, uint32_t reg);
};
struct amdgpu_rlc_reg_funcs {
u32 (*rreg32)(struct amdgpu_device *adev, u32 reg, u32 acc_flags, u32 hwip, u32 xcc_id);
void (*wreg32)(struct amdgpu_device *adev, u32 reg, u32 val, u32 acc_flags, u32 hwip, u32 xcc_id);
};
struct amdgpu_rlcg_reg_access_ctrl {
uint32_t scratch_reg0;
uint32_t scratch_reg1;
@@ -303,6 +308,7 @@ struct amdgpu_rlc {
/* safe mode for updating CG/PG state */
bool in_safe_mode[AMDGPU_MAX_RLC_INSTANCES];
const struct amdgpu_rlc_funcs *funcs;
const struct amdgpu_rlc_reg_funcs *reg_funcs;
/* for firmware data */
u32 save_and_restore_offset;
@@ -374,4 +380,8 @@ void amdgpu_gfx_rlc_fini(struct amdgpu_device *adev);
int amdgpu_gfx_rlc_init_microcode(struct amdgpu_device *adev,
uint16_t version_major,
uint16_t version_minor);
void amdgpu_early_init_rlc_reg_funcs(struct amdgpu_device *adev);
void amdgpu_init_rlc_reg_funcs(struct amdgpu_device *adev);
#endif

View File

@@ -0,0 +1,77 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright 2026 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.
*
*/
#ifndef AMDGPU_SA_H_
#define AMDGPU_SA_H_
#include <drm/drm_suballoc.h>
struct amdgpu_device;
struct amdgpu_bo;
struct amdgpu_sa_manager {
struct drm_suballoc_manager base;
struct amdgpu_bo *bo;
uint64_t gpu_addr;
void *cpu_ptr;
};
static inline struct amdgpu_sa_manager *
to_amdgpu_sa_manager(struct drm_suballoc_manager *manager)
{
return container_of(manager, struct amdgpu_sa_manager, base);
}
static inline uint64_t amdgpu_sa_bo_gpu_addr(struct drm_suballoc *sa_bo)
{
return to_amdgpu_sa_manager(sa_bo->manager)->gpu_addr +
drm_suballoc_soffset(sa_bo);
}
static inline void *amdgpu_sa_bo_cpu_addr(struct drm_suballoc *sa_bo)
{
return to_amdgpu_sa_manager(sa_bo->manager)->cpu_ptr +
drm_suballoc_soffset(sa_bo);
}
int amdgpu_sa_bo_manager_init(struct amdgpu_device *adev,
struct amdgpu_sa_manager *sa_manager,
unsigned size, u32 align, u32 domain);
void amdgpu_sa_bo_manager_fini(struct amdgpu_device *adev,
struct amdgpu_sa_manager *sa_manager);
int amdgpu_sa_bo_manager_start(struct amdgpu_device *adev,
struct amdgpu_sa_manager *sa_manager);
int amdgpu_sa_bo_new(struct amdgpu_sa_manager *sa_manager,
struct drm_suballoc **sa_bo,
unsigned int size);
void amdgpu_sa_bo_free(struct drm_suballoc **sa_bo,
struct dma_fence *fence);
#if defined(CONFIG_DEBUG_FS)
void amdgpu_sa_bo_dump_debug_info(struct amdgpu_sa_manager *sa_manager,
struct seq_file *m);
u64 amdgpu_bo_print_info(int id, struct amdgpu_bo *bo, struct seq_file *m);
#endif
void amdgpu_debugfs_sa_init(struct amdgpu_device *adev);
#endif

View File

@@ -39,7 +39,7 @@ static int amdgpu_sched_process_priority_override(struct amdgpu_device *adev,
struct amdgpu_fpriv *fpriv;
struct amdgpu_ctx_mgr *mgr;
struct amdgpu_ctx *ctx;
uint32_t id;
unsigned long id;
int r;
if (fd_empty(f))
@@ -50,10 +50,10 @@ static int amdgpu_sched_process_priority_override(struct amdgpu_device *adev,
return r;
mgr = &fpriv->ctx_mgr;
mutex_lock(&mgr->lock);
idr_for_each_entry(&mgr->ctx_handles, ctx, id)
xa_lock(&mgr->ctx_handles);
xa_for_each(&mgr->ctx_handles, id, ctx)
amdgpu_ctx_priority_override(ctx, priority);
mutex_unlock(&mgr->lock);
xa_unlock(&mgr->ctx_handles);
return 0;
}

View File

@@ -553,10 +553,11 @@ static int amdgpu_sdma_soft_reset(struct amdgpu_device *adev, u32 instance_id)
int amdgpu_sdma_reset_engine(struct amdgpu_device *adev, uint32_t instance_id,
bool caller_handles_kernel_queues)
{
int ret = 0;
struct amdgpu_sdma_instance *sdma_instance = &adev->sdma.instance[instance_id];
struct amdgpu_ring *gfx_ring = &sdma_instance->ring;
struct amdgpu_ring *page_ring = &sdma_instance->page;
struct amdgpu_fence *gfx_fence, *page_fence;
int ret = 0;
if (amdgpu_sriov_vf(adev))
return -EOPNOTSUPP;
@@ -569,9 +570,14 @@ int amdgpu_sdma_reset_engine(struct amdgpu_device *adev, uint32_t instance_id,
* the reset is in progress.
*/
drm_sched_wqueue_stop(&gfx_ring->sched);
gfx_fence = amdgpu_ring_find_guilty_fence(gfx_ring);
amdgpu_ring_reset_helper_begin(gfx_ring, gfx_fence);
if (adev->sdma.has_page_queue)
if (adev->sdma.has_page_queue) {
drm_sched_wqueue_stop(&page_ring->sched);
page_fence = amdgpu_ring_find_guilty_fence(page_ring);
amdgpu_ring_reset_helper_begin(page_ring, page_fence);
}
}
if (sdma_instance->funcs->stop_kernel_queue) {
@@ -600,14 +606,19 @@ int amdgpu_sdma_reset_engine(struct amdgpu_device *adev, uint32_t instance_id,
* to be submitted to the queues after the reset is complete.
*/
if (!ret) {
amdgpu_fence_driver_force_completion(gfx_ring, NULL);
ret = amdgpu_ring_reset_helper_end(gfx_ring, gfx_fence);
if (ret)
goto unlock;
drm_sched_wqueue_start(&gfx_ring->sched);
if (adev->sdma.has_page_queue) {
amdgpu_fence_driver_force_completion(page_ring, NULL);
ret = amdgpu_ring_reset_helper_end(page_ring, page_fence);
if (ret)
goto unlock;
drm_sched_wqueue_start(&page_ring->sched);
}
}
}
unlock:
mutex_unlock(&sdma_instance->engine_reset_mutex);
return ret;

View File

@@ -85,34 +85,6 @@ struct amdgpu_sdma_instance {
const struct amdgpu_sdma_funcs *funcs;
};
enum amdgpu_sdma_ras_memory_id {
AMDGPU_SDMA_MBANK_DATA_BUF0 = 1,
AMDGPU_SDMA_MBANK_DATA_BUF1 = 2,
AMDGPU_SDMA_MBANK_DATA_BUF2 = 3,
AMDGPU_SDMA_MBANK_DATA_BUF3 = 4,
AMDGPU_SDMA_MBANK_DATA_BUF4 = 5,
AMDGPU_SDMA_MBANK_DATA_BUF5 = 6,
AMDGPU_SDMA_MBANK_DATA_BUF6 = 7,
AMDGPU_SDMA_MBANK_DATA_BUF7 = 8,
AMDGPU_SDMA_MBANK_DATA_BUF8 = 9,
AMDGPU_SDMA_MBANK_DATA_BUF9 = 10,
AMDGPU_SDMA_MBANK_DATA_BUF10 = 11,
AMDGPU_SDMA_MBANK_DATA_BUF11 = 12,
AMDGPU_SDMA_MBANK_DATA_BUF12 = 13,
AMDGPU_SDMA_MBANK_DATA_BUF13 = 14,
AMDGPU_SDMA_MBANK_DATA_BUF14 = 15,
AMDGPU_SDMA_MBANK_DATA_BUF15 = 16,
AMDGPU_SDMA_UCODE_BUF = 17,
AMDGPU_SDMA_RB_CMD_BUF = 18,
AMDGPU_SDMA_IB_CMD_BUF = 19,
AMDGPU_SDMA_UTCL1_RD_FIFO = 20,
AMDGPU_SDMA_UTCL1_RDBST_FIFO = 21,
AMDGPU_SDMA_UTCL1_WR_FIFO = 22,
AMDGPU_SDMA_DATA_LUT_FIFO = 23,
AMDGPU_SDMA_SPLIT_DAT_BUF = 24,
AMDGPU_SDMA_MEMORY_BLOCK_LAST,
};
struct amdgpu_sdma_ras {
struct amdgpu_ras_block_object ras_block;
};

View File

@@ -28,6 +28,8 @@
#include <linux/types.h>
#include <linux/tracepoint.h>
#include "amdgpu_userq_fence.h"
#undef TRACE_SYSTEM
#define TRACE_SYSTEM amdgpu
#define TRACE_INCLUDE_FILE amdgpu_trace
@@ -582,6 +584,154 @@ TRACE_EVENT(amdgpu_reset_reg_dumps,
__entry->value)
);
DECLARE_EVENT_CLASS(amdgpu_userq_queue,
TP_PROTO(struct amdgpu_usermode_queue *queue),
TP_ARGS(queue),
TP_STRUCT__entry(
__field(void *, queue)
__field(u64, doorbell_index)
__field(int, queue_type)
__field(int, state)
__field(u32, xcp_id)
),
TP_fast_assign(
__entry->queue = queue;
__entry->doorbell_index = queue->doorbell_index;
__entry->queue_type = queue->queue_type;
__entry->state = queue->state;
__entry->xcp_id = queue->xcp_id;
),
TP_printk("queue=%p, doorbell=%llu, type=%d, state=%d, xcp_id=%u",
__entry->queue, __entry->doorbell_index,
__entry->queue_type, __entry->state, __entry->xcp_id)
);
DEFINE_EVENT(amdgpu_userq_queue, amdgpu_userq_create_start,
TP_PROTO(struct amdgpu_usermode_queue *queue),
TP_ARGS(queue));
DEFINE_EVENT(amdgpu_userq_queue, amdgpu_userq_destroy_start,
TP_PROTO(struct amdgpu_usermode_queue *queue),
TP_ARGS(queue));
DECLARE_EVENT_CLASS(amdgpu_userq_queue_result,
TP_PROTO(struct amdgpu_usermode_queue *queue, int result),
TP_ARGS(queue, result),
TP_STRUCT__entry(
__field(void *, queue)
__field(u64, doorbell_index)
__field(int, queue_type)
__field(int, state)
__field(u32, xcp_id)
__field(int, result)
),
TP_fast_assign(
__entry->queue = queue;
__entry->doorbell_index = queue->doorbell_index;
__entry->queue_type = queue->queue_type;
__entry->state = queue->state;
__entry->xcp_id = queue->xcp_id;
__entry->result = result;
),
TP_printk("queue=%p, doorbell=%llu, type=%d, state=%d, xcp_id=%u, result=%d",
__entry->queue, __entry->doorbell_index,
__entry->queue_type, __entry->state,
__entry->xcp_id, __entry->result)
);
DEFINE_EVENT(amdgpu_userq_queue_result, amdgpu_userq_create_end,
TP_PROTO(struct amdgpu_usermode_queue *queue, int result),
TP_ARGS(queue, result));
DEFINE_EVENT(amdgpu_userq_queue_result, amdgpu_userq_destroy_end,
TP_PROTO(struct amdgpu_usermode_queue *queue, int result),
TP_ARGS(queue, result));
TRACE_EVENT(amdgpu_userq_emit_fence,
TP_PROTO(struct device *device, struct amdgpu_usermode_queue *queue, struct amdgpu_userq_fence *fence),
TP_ARGS(device, queue, fence),
TP_STRUCT__entry(
__field(u64, fence_context)
__field(u64, fence_seqno)
__string(dev, dev_name(device))
__field(u64, doorbell_index)
__field(u64, client_id)
__field(u32, queue_type)
),
TP_fast_assign(
__entry->fence_context = fence->base.context;
__entry->fence_seqno = fence->base.seqno;
__assign_str(dev);
__entry->doorbell_index = queue->doorbell_index;
__entry->client_id = queue->userq_mgr->file->client_id;
__entry->queue_type = queue->queue_type;
),
TP_printk("dev=%s, client_id=%llu, type=%u, doorbell=%llu, fence=%llu:%llu",
__get_str(dev), __entry->client_id, __entry->queue_type, __entry->doorbell_index,
__entry->fence_context,
__entry->fence_seqno)
);
TRACE_EVENT(amdgpu_userq_wait_deps,
TP_PROTO(struct device *device, struct amdgpu_usermode_queue *queue, struct amdgpu_userq_fence *dep),
TP_ARGS(device, queue, dep),
TP_STRUCT__entry(
__field(u64, context)
__field(u64, dep_context)
__field(u64, dep_seqno)
__string(dev, dev_name(device))
__field(u64, doorbell_index)
__field(u64, client_id)
__field(u32, queue_type)
),
TP_fast_assign(
__assign_str(dev);
__entry->doorbell_index = queue->doorbell_index;
__entry->queue_type = queue->queue_type;
__entry->client_id = queue->userq_mgr->file->client_id;
__entry->context = queue->fence_drv->context;
__entry->dep_context = dep->base.context;
__entry->dep_seqno = dep->base.seqno;
),
TP_printk("dev=%s, client_id=%llu, type=%u, doorbell=%llu, context=%llu depends on fence=%llu:%llu",
__get_str(dev), __entry->client_id, __entry->queue_type, __entry->doorbell_index, __entry->context,
__entry->dep_context,
__entry->dep_seqno)
);
TRACE_EVENT(amdgpu_userq_state_start,
TP_PROTO(struct amdgpu_usermode_queue *queue),
TP_ARGS(queue),
TP_STRUCT__entry(
__field(u64, doorbell_index)
__field(u64, client_id)
__field(u32, queue_type)
__field(u32, from)
),
TP_fast_assign(
__entry->doorbell_index = queue->doorbell_index;
__entry->queue_type = queue->queue_type;
__entry->client_id = queue->userq_mgr->file->client_id;
__entry->from = queue->state;
),
TP_printk("client_id=%llu, type=%u, doorbell=%llu, from=%d",
__entry->client_id, __entry->queue_type, __entry->doorbell_index, __entry->from)
);
TRACE_EVENT(amdgpu_userq_state_changed,
TP_PROTO(struct amdgpu_usermode_queue *queue, enum amdgpu_userq_state new_state),
TP_ARGS(queue, new_state),
TP_STRUCT__entry(
__field(u64, doorbell_index)
__field(u64, client_id)
__field(u32, queue_type)
__field(u32, to)
),
TP_fast_assign(
__entry->doorbell_index = queue->doorbell_index;
__entry->queue_type = queue->queue_type;
__entry->client_id = queue->userq_mgr->file->client_id;
__entry->to = new_state;
),
TP_printk("client_id=%llu, type=%u, doorbell=%llu, to=%d",
__entry->client_id, __entry->queue_type, __entry->doorbell_index, __entry->to)
);
#undef AMDGPU_JOB_GET_TIMELINE_NAME
#endif

View File

@@ -2194,7 +2194,7 @@ int amdgpu_ttm_init(struct amdgpu_device *adev)
return r;
}
/* Create a boorbell page for kernel usages */
/* Create a doorbell page for kernel usages */
r = amdgpu_doorbell_create_kernel_doorbells(adev);
if (r) {
dev_err(adev->dev, "Failed to initialize kernel doorbells.\n");

View File

@@ -140,6 +140,7 @@ int amdgpu_gtt_mgr_init(struct amdgpu_device *adev, uint64_t gtt_size);
void amdgpu_gtt_mgr_fini(struct amdgpu_device *adev);
int amdgpu_preempt_mgr_init(struct amdgpu_device *adev);
void amdgpu_preempt_mgr_fini(struct amdgpu_device *adev);
void amdgpu_preempt_mgr_sysfs_fini(struct amdgpu_device *adev);
int amdgpu_vram_mgr_init(struct amdgpu_device *adev);
void amdgpu_vram_mgr_fini(struct amdgpu_device *adev);

View File

@@ -97,7 +97,6 @@ void amdgpu_umc_handle_bad_pages(struct amdgpu_device *adev,
{
struct ras_err_data *err_data = (struct ras_err_data *)ras_error_status;
struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
struct amdgpu_ras_eeprom_control *control = &con->eeprom_control;
unsigned int error_query_mode;
int ret = 0;
unsigned long err_count;
@@ -118,77 +117,66 @@ void amdgpu_umc_handle_bad_pages(struct amdgpu_device *adev,
err_data->err_addr_len = adev->umc.max_ras_err_cnt_per_query;
mutex_lock(&con->page_retirement_lock);
if (!amdgpu_ras_smu_eeprom_supported(adev)) {
ret = amdgpu_dpm_get_ecc_info(adev, (void *)&(con->umc_ecc));
if (ret == -EOPNOTSUPP &&
error_query_mode == AMDGPU_RAS_DIRECT_ERROR_QUERY) {
if (adev->umc.ras && adev->umc.ras->ras_block.hw_ops &&
adev->umc.ras->ras_block.hw_ops->query_ras_error_count)
adev->umc.ras->ras_block.hw_ops->query_ras_error_count(adev,
ras_error_status);
ret = amdgpu_dpm_get_ecc_info(adev, (void *)&(con->umc_ecc));
if (ret == -EOPNOTSUPP &&
error_query_mode == AMDGPU_RAS_DIRECT_ERROR_QUERY) {
if (adev->umc.ras && adev->umc.ras->ras_block.hw_ops &&
adev->umc.ras->ras_block.hw_ops->query_ras_error_count)
adev->umc.ras->ras_block.hw_ops->query_ras_error_count(adev,
ras_error_status);
if (adev->umc.ras && adev->umc.ras->ras_block.hw_ops &&
adev->umc.ras->ras_block.hw_ops->query_ras_error_address &&
adev->umc.max_ras_err_cnt_per_query) {
kfree(err_data->err_addr);
err_data->err_addr =
kzalloc_objs(struct eeprom_table_record,
adev->umc.max_ras_err_cnt_per_query);
if (adev->umc.ras && adev->umc.ras->ras_block.hw_ops &&
adev->umc.ras->ras_block.hw_ops->query_ras_error_address &&
adev->umc.max_ras_err_cnt_per_query) {
err_data->err_addr =
kzalloc_objs(struct eeprom_table_record,
adev->umc.max_ras_err_cnt_per_query);
/* still call query_ras_error_address to clear error status
* even NOMEM error is encountered
*/
if (!err_data->err_addr)
dev_warn(adev->dev,
"Failed to alloc memory for umc error address record!\n");
else
err_data->err_addr_len =
adev->umc.max_ras_err_cnt_per_query;
/* still call query_ras_error_address to clear error status
* even NOMEM error is encountered
*/
if (!err_data->err_addr)
dev_warn(adev->dev,
"Failed to alloc memory for umc error address record!\n");
else
err_data->err_addr_len =
adev->umc.max_ras_err_cnt_per_query;
/* umc query_ras_error_address is also responsible for clearing
* error status
*/
adev->umc.ras->ras_block.hw_ops->query_ras_error_address(adev,
ras_error_status);
}
} else if (error_query_mode == AMDGPU_RAS_FIRMWARE_ERROR_QUERY ||
(!ret && error_query_mode == AMDGPU_RAS_DIRECT_ERROR_QUERY)) {
if (adev->umc.ras &&
adev->umc.ras->ecc_info_query_ras_error_count)
adev->umc.ras->ecc_info_query_ras_error_count(adev,
ras_error_status);
if (adev->umc.ras &&
adev->umc.ras->ecc_info_query_ras_error_address &&
adev->umc.max_ras_err_cnt_per_query) {
kfree(err_data->err_addr);
err_data->err_addr =
kzalloc_objs(struct eeprom_table_record,
adev->umc.max_ras_err_cnt_per_query);
/* still call query_ras_error_address to clear error status
* even NOMEM error is encountered
*/
if (!err_data->err_addr)
dev_warn(adev->dev,
"Failed to alloc memory for umc error address record!\n");
else
err_data->err_addr_len =
adev->umc.max_ras_err_cnt_per_query;
/* umc query_ras_error_address is also responsible for clearing
* error status
*/
adev->umc.ras->ecc_info_query_ras_error_address(adev,
ras_error_status);
}
/* umc query_ras_error_address is also responsible for clearing
* error status
*/
adev->umc.ras->ras_block.hw_ops->query_ras_error_address(adev,
ras_error_status);
}
} else {
if (!amdgpu_ras_eeprom_update_record_num(control)) {
err_data->err_addr_cnt = err_data->de_count =
control->ras_num_recs - control->ras_num_recs_old;
amdgpu_ras_eeprom_read_idx(control, err_data->err_addr,
control->ras_num_recs_old, err_data->de_count);
} else if (error_query_mode == AMDGPU_RAS_FIRMWARE_ERROR_QUERY ||
(!ret && error_query_mode == AMDGPU_RAS_DIRECT_ERROR_QUERY)) {
if (adev->umc.ras &&
adev->umc.ras->ecc_info_query_ras_error_count)
adev->umc.ras->ecc_info_query_ras_error_count(adev,
ras_error_status);
if (adev->umc.ras &&
adev->umc.ras->ecc_info_query_ras_error_address &&
adev->umc.max_ras_err_cnt_per_query) {
err_data->err_addr =
kcalloc(adev->umc.max_ras_err_cnt_per_query,
sizeof(struct eeprom_table_record), GFP_KERNEL);
/* still call query_ras_error_address to clear error status
* even NOMEM error is encountered
*/
if (!err_data->err_addr)
dev_warn(adev->dev,
"Failed to alloc memory for umc error address record!\n");
else
err_data->err_addr_len =
adev->umc.max_ras_err_cnt_per_query;
/* umc query_ras_error_address is also responsible for clearing
* error status
*/
adev->umc.ras->ecc_info_query_ras_error_address(adev,
ras_error_status);
}
}
@@ -276,7 +264,7 @@ int amdgpu_umc_pasid_poison_handler(struct amdgpu_device *adev,
}
amdgpu_ras_error_data_fini(&err_data);
} else if (amdgpu_uniras_enabled(adev)) {
} else {
struct ras_ih_info ih_info = {0};
ih_info.block = block;
@@ -285,17 +273,6 @@ int amdgpu_umc_pasid_poison_handler(struct amdgpu_device *adev,
ih_info.pasid_fn = pasid_fn;
ih_info.data = data;
amdgpu_ras_mgr_handle_consumer_interrupt(adev, &ih_info);
} else {
struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
int ret;
ret = amdgpu_ras_put_poison_req(adev,
block, pasid, pasid_fn, data, reset);
if (!ret) {
atomic_inc(&con->page_retirement_req_cnt);
atomic_inc(&con->poison_consumption_count);
wake_up(&con->page_retirement_wq);
}
}
} else {
if (adev->virt.ops && adev->virt.ops->ras_poison_handler)
@@ -512,129 +489,3 @@ int amdgpu_umc_loop_channels(struct amdgpu_device *adev,
return 0;
}
int amdgpu_umc_update_ecc_status(struct amdgpu_device *adev,
uint64_t status, uint64_t ipid, uint64_t addr)
{
if (adev->umc.ras->update_ecc_status)
return adev->umc.ras->update_ecc_status(adev,
status, ipid, addr);
return 0;
}
int amdgpu_umc_logs_ecc_err(struct amdgpu_device *adev,
struct radix_tree_root *ecc_tree, struct ras_ecc_err *ecc_err)
{
struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
struct ras_ecc_log_info *ecc_log;
int ret;
ecc_log = &con->umc_ecc_log;
mutex_lock(&ecc_log->lock);
ret = radix_tree_insert(ecc_tree, ecc_err->pa_pfn, ecc_err);
if (!ret)
radix_tree_tag_set(ecc_tree,
ecc_err->pa_pfn, UMC_ECC_NEW_DETECTED_TAG);
mutex_unlock(&ecc_log->lock);
return ret;
}
int amdgpu_umc_pages_in_a_row(struct amdgpu_device *adev,
struct ras_err_data *err_data, uint64_t pa_addr)
{
struct ta_ras_query_address_output addr_out;
/* reinit err_data */
err_data->err_addr_cnt = 0;
err_data->err_addr_len = adev->umc.retire_unit;
addr_out.pa.pa = pa_addr;
if (adev->umc.ras && adev->umc.ras->convert_ras_err_addr)
return adev->umc.ras->convert_ras_err_addr(adev, err_data, NULL,
&addr_out, false);
else
return -EINVAL;
}
int amdgpu_umc_lookup_bad_pages_in_a_row(struct amdgpu_device *adev,
uint64_t pa_addr, uint64_t *pfns, int len)
{
int i, ret;
struct ras_err_data err_data;
err_data.err_addr = kzalloc_objs(struct eeprom_table_record,
adev->umc.retire_unit);
if (!err_data.err_addr) {
dev_warn(adev->dev, "Failed to alloc memory in bad page lookup!\n");
return 0;
}
ret = amdgpu_umc_pages_in_a_row(adev, &err_data, pa_addr);
if (ret)
goto out;
for (i = 0; i < adev->umc.retire_unit; i++) {
if (i >= len)
goto out;
pfns[i] = err_data.err_addr[i].retired_page;
}
ret = i;
adev->umc.err_addr_cnt = err_data.err_addr_cnt;
out:
kfree(err_data.err_addr);
return ret;
}
int amdgpu_umc_mca_to_addr(struct amdgpu_device *adev,
uint64_t err_addr, uint32_t ch, uint32_t umc,
uint32_t node, uint32_t socket,
struct ta_ras_query_address_output *addr_out, bool dump_addr)
{
struct ta_ras_query_address_input addr_in;
int ret;
memset(&addr_in, 0, sizeof(addr_in));
addr_in.ma.err_addr = err_addr;
addr_in.ma.ch_inst = ch;
addr_in.ma.umc_inst = umc;
addr_in.ma.node_inst = node;
addr_in.ma.socket_id = socket;
if (adev->umc.ras && adev->umc.ras->convert_ras_err_addr) {
ret = adev->umc.ras->convert_ras_err_addr(adev, NULL, &addr_in,
addr_out, dump_addr);
if (ret)
return ret;
} else {
return 0;
}
return 0;
}
int amdgpu_umc_pa2mca(struct amdgpu_device *adev,
uint64_t pa, uint64_t *mca, enum amdgpu_memory_partition nps)
{
struct ta_ras_query_address_input addr_in;
struct ta_ras_query_address_output addr_out;
int ret;
/* nps: the pa belongs to */
addr_in.pa.pa = pa | ((uint64_t)nps << 58);
addr_in.addr_type = TA_RAS_PA_TO_MCA;
ret = psp_ras_query_address(&adev->psp, &addr_in, &addr_out);
if (ret) {
dev_warn(adev->dev, "Failed to query RAS MCA address for 0x%llx",
pa);
return ret;
}
*mca = addr_out.ma.err_addr;
return 0;
}

View File

@@ -103,18 +103,7 @@ struct amdgpu_umc_ras {
void *ras_error_status);
bool (*check_ecc_err_status)(struct amdgpu_device *adev,
enum amdgpu_mca_error_type type, void *ras_error_status);
int (*update_ecc_status)(struct amdgpu_device *adev,
uint64_t status, uint64_t ipid, uint64_t addr);
int (*convert_ras_err_addr)(struct amdgpu_device *adev,
struct ras_err_data *err_data,
struct ta_ras_query_address_input *addr_in,
struct ta_ras_query_address_output *addr_out,
bool dump_addr);
uint32_t (*get_die_id_from_pa)(struct amdgpu_device *adev,
uint64_t mca_addr, uint64_t retired_page);
void (*get_retire_flip_bits)(struct amdgpu_device *adev);
void (*mca_ipid_parse)(struct amdgpu_device *adev, uint64_t ipid,
uint32_t *did, uint32_t *ch, uint32_t *umc_inst, uint32_t *sid);
};
struct amdgpu_umc_funcs {
@@ -179,21 +168,6 @@ int amdgpu_umc_page_retirement_mca(struct amdgpu_device *adev,
int amdgpu_umc_loop_channels(struct amdgpu_device *adev,
umc_func func, void *data);
int amdgpu_umc_update_ecc_status(struct amdgpu_device *adev,
uint64_t status, uint64_t ipid, uint64_t addr);
int amdgpu_umc_logs_ecc_err(struct amdgpu_device *adev,
struct radix_tree_root *ecc_tree, struct ras_ecc_err *ecc_err);
void amdgpu_umc_handle_bad_pages(struct amdgpu_device *adev,
void *ras_error_status);
int amdgpu_umc_pages_in_a_row(struct amdgpu_device *adev,
struct ras_err_data *err_data, uint64_t pa_addr);
int amdgpu_umc_lookup_bad_pages_in_a_row(struct amdgpu_device *adev,
uint64_t pa_addr, uint64_t *pfns, int len);
int amdgpu_umc_mca_to_addr(struct amdgpu_device *adev,
uint64_t err_addr, uint32_t ch, uint32_t umc,
uint32_t node, uint32_t socket,
struct ta_ras_query_address_output *addr_out, bool dump_addr);
int amdgpu_umc_pa2mca(struct amdgpu_device *adev,
uint64_t pa, uint64_t *mca, enum amdgpu_memory_partition nps);
#endif

View File

@@ -33,6 +33,7 @@
#include "amdgpu_userq.h"
#include "amdgpu_hmm.h"
#include "amdgpu_userq_fence.h"
#include "amdgpu_trace.h"
u32 amdgpu_userq_get_supported_ip_mask(struct amdgpu_device *adev)
{
@@ -88,14 +89,7 @@ static void amdgpu_userq_mgr_reset_work(struct work_struct *work)
container_of(work, struct amdgpu_userq_mgr,
reset_work);
struct amdgpu_device *adev = uq_mgr->adev;
const int queue_types[] = {
AMDGPU_RING_TYPE_COMPUTE,
AMDGPU_RING_TYPE_GFX,
AMDGPU_RING_TYPE_SDMA
};
const int num_queue_types = ARRAY_SIZE(queue_types);
bool gpu_reset = false;
int i, r;
struct amdgpu_reset_context reset_context;
if (unlikely(adev->debug_disable_gpu_ring_reset)) {
dev_err(adev->dev, "userq reset disabled by debug mask\n");
@@ -109,42 +103,15 @@ static void amdgpu_userq_mgr_reset_work(struct work_struct *work)
if (!amdgpu_gpu_recovery)
return;
/*
* Iterate through all queue types to detect and reset problematic queues
* Process each queue type in the defined order
*/
for (i = 0; i < num_queue_types; i++) {
int ring_type = queue_types[i];
const struct amdgpu_userq_funcs *funcs =
adev->userq_funcs[ring_type];
memset(&reset_context, 0, sizeof(reset_context));
if (!amdgpu_userq_is_reset_type_supported(adev, ring_type,
AMDGPU_RESET_TYPE_PER_QUEUE))
continue;
reset_context.method = AMD_RESET_METHOD_NONE;
reset_context.reset_req_dev = adev;
reset_context.src = AMDGPU_RESET_SRC_USERQ;
set_bit(AMDGPU_NEED_FULL_RESET, &reset_context.flags);
/*set_bit(AMDGPU_SKIP_COREDUMP, &reset_context.flags);*/
if (atomic_read(&uq_mgr->userq_count[ring_type]) > 0 &&
funcs && funcs->detect_and_reset) {
r = funcs->detect_and_reset(adev, ring_type);
if (r) {
gpu_reset = true;
break;
}
}
}
if (gpu_reset) {
struct amdgpu_reset_context reset_context;
memset(&reset_context, 0, sizeof(reset_context));
reset_context.method = AMD_RESET_METHOD_NONE;
reset_context.reset_req_dev = adev;
reset_context.src = AMDGPU_RESET_SRC_USERQ;
set_bit(AMDGPU_NEED_FULL_RESET, &reset_context.flags);
/*set_bit(AMDGPU_SKIP_COREDUMP, &reset_context.flags);*/
amdgpu_device_gpu_recover(adev, NULL, &reset_context);
}
amdgpu_device_gpu_recover(adev, NULL, &reset_context);
}
static void amdgpu_userq_hang_detect_work(struct work_struct *work)
@@ -152,12 +119,45 @@ static void amdgpu_userq_hang_detect_work(struct work_struct *work)
struct amdgpu_usermode_queue *queue =
container_of(work, struct amdgpu_usermode_queue,
hang_detect_work.work);
struct amdgpu_userq_mgr *uq_mgr = queue->userq_mgr;
struct amdgpu_device *adev = uq_mgr->adev;
const struct amdgpu_userq_funcs *userq_funcs =
adev->userq_funcs[queue->queue_type];
bool gpu_reset = false;
if (unlikely(adev->debug_disable_gpu_ring_reset)) {
dev_err(adev->dev, "userq reset disabled by debug mask\n");
return;
}
/*
* If GPU recovery feature is disabled system-wide,
* skip all reset detection logic
*/
if (!amdgpu_gpu_recovery)
return;
if (amdgpu_userq_is_reset_type_supported(adev, queue->queue_type,
AMDGPU_RESET_TYPE_PER_QUEUE)) {
int r;
if (queue->queue_type == AMDGPU_HW_IP_COMPUTE)
r = amdgpu_gfx_reset_mes_compute(adev, NULL, NULL,
queue, NULL, NULL);
else
r = userq_funcs->reset(queue);
if (r)
gpu_reset = true;
} else {
gpu_reset = true;
}
/*
* Don't schedule the work here! Scheduling or queue work from one reset
* handler to another is illegal if you don't take extra precautions!
*/
amdgpu_userq_mgr_reset_work(&queue->userq_mgr->reset_work);
if (gpu_reset)
amdgpu_userq_mgr_reset_work(&queue->userq_mgr->reset_work);
}
/*
@@ -293,11 +293,15 @@ static int amdgpu_userq_preempt_helper(struct amdgpu_usermode_queue *queue)
int r;
if (queue->state == AMDGPU_USERQ_STATE_MAPPED) {
trace_amdgpu_userq_state_start(queue);
r = userq_funcs->preempt(queue);
if (r) {
trace_amdgpu_userq_state_changed(queue, AMDGPU_USERQ_STATE_HUNG);
queue->state = AMDGPU_USERQ_STATE_HUNG;
return r;
} else {
trace_amdgpu_userq_state_changed(queue, AMDGPU_USERQ_STATE_PREEMPTED);
queue->state = AMDGPU_USERQ_STATE_PREEMPTED;
}
}
@@ -313,10 +317,14 @@ static int amdgpu_userq_restore_helper(struct amdgpu_usermode_queue *queue)
int r = 0;
if (queue->state == AMDGPU_USERQ_STATE_PREEMPTED) {
trace_amdgpu_userq_state_start(queue);
r = userq_funcs->restore(queue);
if (r) {
trace_amdgpu_userq_state_changed(queue, AMDGPU_USERQ_STATE_HUNG);
queue->state = AMDGPU_USERQ_STATE_HUNG;
} else {
trace_amdgpu_userq_state_changed(queue, AMDGPU_USERQ_STATE_MAPPED);
queue->state = AMDGPU_USERQ_STATE_MAPPED;
}
}
@@ -334,12 +342,15 @@ static int amdgpu_userq_unmap_helper(struct amdgpu_usermode_queue *queue)
if ((queue->state == AMDGPU_USERQ_STATE_MAPPED) ||
(queue->state == AMDGPU_USERQ_STATE_PREEMPTED)) {
trace_amdgpu_userq_state_start(queue);
r = userq_funcs->unmap(queue);
if (r) {
trace_amdgpu_userq_state_changed(queue, AMDGPU_USERQ_STATE_HUNG);
queue->state = AMDGPU_USERQ_STATE_HUNG;
return r;
} else {
trace_amdgpu_userq_state_changed(queue, AMDGPU_USERQ_STATE_UNMAPPED);
queue->state = AMDGPU_USERQ_STATE_UNMAPPED;
}
}
@@ -356,11 +367,15 @@ static int amdgpu_userq_map_helper(struct amdgpu_usermode_queue *queue)
int r;
if (queue->state == AMDGPU_USERQ_STATE_UNMAPPED) {
trace_amdgpu_userq_state_start(queue);
r = userq_funcs->map(queue);
if (r) {
trace_amdgpu_userq_state_changed(queue, AMDGPU_USERQ_STATE_HUNG);
queue->state = AMDGPU_USERQ_STATE_HUNG;
return r;
} else {
trace_amdgpu_userq_state_changed(queue, AMDGPU_USERQ_STATE_MAPPED);
queue->state = AMDGPU_USERQ_STATE_MAPPED;
}
}
@@ -507,6 +522,8 @@ amdgpu_userq_destroy(struct amdgpu_userq_mgr *uq_mgr, struct amdgpu_usermode_que
const struct amdgpu_userq_funcs *uq_funcs = adev->userq_funcs[queue->queue_type];
int r = 0;
trace_amdgpu_userq_destroy_start(queue);
cancel_delayed_work_sync(&uq_mgr->resume_work);
/* Cancel any pending hang detection work and cleanup */
@@ -532,6 +549,7 @@ amdgpu_userq_destroy(struct amdgpu_userq_mgr *uq_mgr, struct amdgpu_usermode_que
amdgpu_bo_unreserve(queue->db_obj.obj);
amdgpu_bo_unref(&queue->db_obj.obj);
trace_amdgpu_userq_destroy_end(queue, r);
kfree(queue);
pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
@@ -629,6 +647,8 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args)
queue->queue_type = args->in.ip_type;
queue->vm = &fpriv->vm;
queue->priority = priority;
queue->xcp_id = (fpriv->xcp_id != AMDGPU_XCP_NO_PARTITION) ?
fpriv->xcp_id : 0;
queue->userq_mgr = uq_mgr;
INIT_DELAYED_WORK(&queue->hang_detect_work,
amdgpu_userq_hang_detect_work);
@@ -671,6 +691,8 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args)
}
queue->doorbell_index = index;
queue->doorbell_offset = (u32)args->in.doorbell_offset;
trace_amdgpu_userq_create_start(queue);
r = uq_funcs->mqd_create(queue, &args->in);
if (r) {
drm_file_err(uq_mgr->file, "Failed to create Queue\n");
@@ -694,6 +716,7 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args)
r = amdgpu_userq_map_helper(queue);
if (r) {
drm_file_err(uq_mgr->file, "Failed to map Queue\n");
trace_amdgpu_userq_create_end(queue, r);
mutex_unlock(&uq_mgr->userq_mutex);
goto erase_doorbell;
}
@@ -710,11 +733,13 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args)
* This drops the last reference which should take care of
* all cleanup.
*/
trace_amdgpu_userq_create_end(queue, r);
amdgpu_userq_put(queue);
return r;
}
amdgpu_debugfs_userq_init(filp, queue, qid);
trace_amdgpu_userq_create_end(queue, 0);
args->out.queue_id = qid;
return 0;
@@ -730,6 +755,7 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args)
free_fence_drv:
amdgpu_userq_fence_driver_free(queue);
free_queue:
trace_amdgpu_userq_create_end(queue, r);
kfree(queue);
err_pm_runtime:
pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
@@ -862,16 +888,10 @@ int amdgpu_userq_ioctl(struct drm_device *dev, void *data,
static int
amdgpu_userq_restore_all(struct amdgpu_userq_mgr *uq_mgr)
{
struct amdgpu_fpriv *fpriv = uq_mgr_to_fpriv(uq_mgr);
struct amdgpu_vm *vm = &fpriv->vm;
struct amdgpu_usermode_queue *queue;
unsigned long queue_id;
int ret = 0, r;
if (amdgpu_bo_reserve(vm->root.bo, false))
return false;
mutex_lock(&uq_mgr->userq_mutex);
/* Resume all the queues for this process */
xa_for_each(&uq_mgr->userq_xa, queue_id, queue) {
@@ -879,6 +899,7 @@ amdgpu_userq_restore_all(struct amdgpu_userq_mgr *uq_mgr)
if (!amdgpu_userq_buffer_vas_mapped(queue)) {
drm_file_err(uq_mgr->file,
"trying restore queue without va mapping\n");
trace_amdgpu_userq_state_changed(queue, AMDGPU_USERQ_STATE_INVALID_VA);
queue->state = AMDGPU_USERQ_STATE_INVALID_VA;
continue;
}
@@ -886,10 +907,8 @@ amdgpu_userq_restore_all(struct amdgpu_userq_mgr *uq_mgr)
r = amdgpu_userq_map_helper(queue);
if (r)
ret = r;
}
mutex_unlock(&uq_mgr->userq_mutex);
amdgpu_bo_unreserve(vm->root.bo);
if (ret)
drm_file_err(uq_mgr->file,
@@ -923,7 +942,8 @@ amdgpu_userq_bo_validate(struct amdgpu_device *adev, struct drm_exec *exec,
spin_unlock(&vm->individual_lock);
bo = bo_va->base.bo;
ret = drm_exec_prepare_obj(exec, &bo->tbo.base, 2);
ret = drm_exec_prepare_obj(exec, &bo->tbo.base,
TTM_NUM_MOVE_FENCES + 1);
if (unlikely(ret))
return ret;
@@ -946,7 +966,7 @@ amdgpu_userq_bo_validate(struct amdgpu_device *adev, struct drm_exec *exec,
/* Make sure the whole VM is ready to be used */
static int
amdgpu_userq_vm_validate(struct amdgpu_userq_mgr *uq_mgr)
amdgpu_userq_vm_validate_and_restore_queue(struct amdgpu_userq_mgr *uq_mgr)
{
struct amdgpu_fpriv *fpriv = uq_mgr_to_fpriv(uq_mgr);
bool invalidated = false, new_addition = false;
@@ -1072,8 +1092,12 @@ amdgpu_userq_vm_validate(struct amdgpu_userq_mgr *uq_mgr)
dma_fence_wait(vm->last_update, false);
ret = amdgpu_evf_mgr_rearm(&fpriv->evf_mgr, &exec);
if (ret)
if (ret) {
drm_file_err(uq_mgr->file, "Failed to replace eviction fence\n");
goto unlock_all;
}
ret = amdgpu_userq_restore_all(uq_mgr);
unlock_all:
drm_exec_fini(&exec);
@@ -1099,18 +1123,34 @@ static void amdgpu_userq_restore_worker(struct work_struct *work)
if (!dma_fence_is_signaled(ev_fence))
goto put_fence;
ret = amdgpu_userq_vm_validate(uq_mgr);
ret = amdgpu_userq_vm_validate_and_restore_queue(uq_mgr);
if (ret) {
drm_file_err(uq_mgr->file, "Failed to validate BOs to restore ret=%d\n", ret);
goto put_fence;
}
amdgpu_userq_restore_all(uq_mgr);
put_fence:
dma_fence_put(ev_fence);
}
void amdgpu_userq_process_reset_irq(struct amdgpu_device *adev,
u32 pasid, u32 doorbell_offset)
{
struct xarray *xa = &adev->userq_doorbell_xa;
struct amdgpu_usermode_queue *queue;
unsigned long flags, idx;
xa_lock_irqsave(xa, flags);
xa_for_each(xa, idx, queue) {
if (queue->vm && queue->vm->pasid == pasid &&
queue->doorbell_offset == doorbell_offset) {
amdgpu_userq_start_hang_detect_work(queue);
break;
}
}
xa_unlock_irqrestore(xa, flags);
}
static int
amdgpu_userq_evict_all(struct amdgpu_userq_mgr *uq_mgr)
{
@@ -1166,6 +1206,7 @@ int amdgpu_userq_mgr_init(struct amdgpu_userq_mgr *userq_mgr, struct drm_file *f
xa_init_flags(&userq_mgr->userq_xa, XA_FLAGS_ALLOC);
userq_mgr->adev = adev;
userq_mgr->file = file_priv;
mutex_init(&userq_mgr->proc_ctx_lock);
INIT_DELAYED_WORK(&userq_mgr->resume_work, amdgpu_userq_restore_worker);
INIT_WORK(&userq_mgr->reset_work, amdgpu_userq_mgr_reset_work);
@@ -1219,6 +1260,11 @@ void amdgpu_userq_mgr_fini(struct amdgpu_userq_mgr *userq_mgr)
*/
cancel_work_sync(&userq_mgr->reset_work);
amdgpu_bo_free_kernel(&userq_mgr->proc_ctx_obj.obj,
&userq_mgr->proc_ctx_obj.gpu_addr,
&userq_mgr->proc_ctx_obj.cpu_ptr);
mutex_destroy(&userq_mgr->proc_ctx_lock);
mutex_destroy(&userq_mgr->userq_mutex);
}
@@ -1370,12 +1416,14 @@ void amdgpu_userq_pre_reset(struct amdgpu_device *adev)
if (queue->state != AMDGPU_USERQ_STATE_MAPPED)
continue;
trace_amdgpu_userq_state_start(queue);
userq_funcs = adev->userq_funcs[queue->queue_type];
userq_funcs->unmap(queue);
/* just mark all queues as hung at this point.
* if unmap succeeds, we could map again
* in amdgpu_userq_post_reset() if vram is not lost
*/
trace_amdgpu_userq_state_changed(queue, AMDGPU_USERQ_STATE_HUNG);
queue->state = AMDGPU_USERQ_STATE_HUNG;
amdgpu_userq_fence_driver_force_completion(queue);
}
@@ -1394,6 +1442,8 @@ int amdgpu_userq_post_reset(struct amdgpu_device *adev, bool vram_lost)
xa_for_each(&adev->userq_doorbell_xa, queue_id, queue) {
if (queue->state == AMDGPU_USERQ_STATE_HUNG && !vram_lost) {
trace_amdgpu_userq_state_start(queue);
userq_funcs = adev->userq_funcs[queue->queue_type];
/* Re-map queue */
r = userq_funcs->map(queue);
@@ -1401,6 +1451,7 @@ int amdgpu_userq_post_reset(struct amdgpu_device *adev, bool vram_lost)
dev_err(adev->dev, "Failed to remap queue %ld\n", queue_id);
continue;
}
trace_amdgpu_userq_state_changed(queue, AMDGPU_USERQ_STATE_MAPPED);
queue->state = AMDGPU_USERQ_STATE_MAPPED;
}
}

View File

@@ -53,6 +53,7 @@ struct amdgpu_usermode_queue {
enum amdgpu_userq_state state;
uint64_t doorbell_handle;
uint64_t doorbell_index;
u32 doorbell_offset;
uint64_t flags;
struct amdgpu_mqd_prop *userq_prop;
struct amdgpu_userq_mgr *userq_mgr;
@@ -111,8 +112,7 @@ struct amdgpu_userq_funcs {
int (*map)(struct amdgpu_usermode_queue *queue);
int (*preempt)(struct amdgpu_usermode_queue *queue);
int (*restore)(struct amdgpu_usermode_queue *queue);
int (*detect_and_reset)(struct amdgpu_device *adev,
int queue_type);
int (*reset)(struct amdgpu_usermode_queue *queue);
};
/* Usermode queues for gfx */
@@ -127,6 +127,8 @@ struct amdgpu_userq_mgr {
struct amdgpu_device *adev;
struct delayed_work resume_work;
struct drm_file *file;
struct mutex proc_ctx_lock;
struct amdgpu_userq_obj proc_ctx_obj;
/**
* @reset_work:
@@ -177,6 +179,16 @@ int amdgpu_userq_post_reset(struct amdgpu_device *adev, bool vram_lost);
void amdgpu_userq_start_hang_detect_work(struct amdgpu_usermode_queue *queue);
void amdgpu_userq_process_fence_irq(struct amdgpu_device *adev, u32 doorbell);
/*
* CP packs the per-process doorbell_id of the queue in
* CTXID0[9:0] on priv-fault (same encoding KFD uses via
* KFD_CTXID0_DOORBELL_ID_MASK)
*/
#define AMDGPU_CTXID0_DOORBELL_ID_MASK 0x3ff
void amdgpu_userq_process_reset_irq(struct amdgpu_device *adev,
u32 pasid, u32 doorbell_offset);
int amdgpu_userq_input_va_validate(struct amdgpu_device *adev,
struct amdgpu_usermode_queue *queue,
u64 addr, u64 expected_size, u64 *va_out);

View File

@@ -30,7 +30,7 @@
#include <drm/drm_syncobj.h>
#include "amdgpu.h"
#include "amdgpu_userq_fence.h"
#include "amdgpu_trace.h"
#define AMDGPU_USERQ_MAX_HANDLES (1U << 16)
@@ -528,6 +528,8 @@ int amdgpu_userq_signal_ioctl(struct drm_device *dev, void *data,
/* Create the new fence */
amdgpu_userq_fence_init(queue, fence, wptr);
trace_amdgpu_userq_emit_fence(dev->dev, queue, fence);
mutex_unlock(&userq_mgr->userq_mutex);
/*
@@ -701,7 +703,7 @@ amdgpu_userq_wait_add_fence(struct drm_amdgpu_userq_wait *wait_info,
}
static int
amdgpu_userq_wait_return_fence_info(struct drm_file *filp,
amdgpu_userq_wait_return_fence_info(struct drm_device *dev, struct drm_file *filp,
struct drm_amdgpu_userq_wait *wait_info,
u32 *syncobj_handles, u64 *timeline_points,
u32 *timeline_handles,
@@ -869,6 +871,8 @@ amdgpu_userq_wait_return_fence_info(struct drm_file *filp,
amdgpu_userq_fence_driver_get(fence_drv);
trace_amdgpu_userq_wait_deps(dev->dev, waitq, userq_fence);
/* Store drm syncobj's gpu va address and value */
fence_info[cnt].va = fence_drv->va;
fence_info[cnt].value = fences[i]->seqno;
@@ -969,7 +973,7 @@ int amdgpu_userq_wait_ioctl(struct drm_device *dev, void *data,
gobj_write,
gobj_read);
} else {
r = amdgpu_userq_wait_return_fence_info(filp, wait_info,
r = amdgpu_userq_wait_return_fence_info(dev, filp, wait_info,
syncobj_handles,
timeline_points,
timeline_handles,

View File

@@ -506,9 +506,8 @@ void amdgpu_vcn_ring_begin_use(struct amdgpu_ring *ring)
struct amdgpu_device *adev = ring->adev;
struct amdgpu_vcn_inst *vcn_inst = &adev->vcn.inst[ring->me];
atomic_inc(&vcn_inst->total_submission_cnt);
cancel_delayed_work_sync(&vcn_inst->idle_work);
if (!atomic_fetch_inc(&vcn_inst->total_submission_cnt))
cancel_delayed_work_sync(&vcn_inst->idle_work);
mutex_lock(&vcn_inst->vcn_pg_lock);
vcn_inst->set_pg_state(vcn_inst, AMD_PG_STATE_UNGATE);
@@ -550,10 +549,9 @@ void amdgpu_vcn_ring_end_use(struct amdgpu_ring *ring)
!adev->vcn.inst[ring->me].using_unified_queue)
atomic_dec(&ring->adev->vcn.inst[ring->me].dpg_enc_submission_cnt);
atomic_dec(&ring->adev->vcn.inst[ring->me].total_submission_cnt);
schedule_delayed_work(&ring->adev->vcn.inst[ring->me].idle_work,
VCN_IDLE_TIMEOUT);
if (atomic_dec_and_test(&ring->adev->vcn.inst[ring->me].total_submission_cnt))
schedule_delayed_work(&ring->adev->vcn.inst[ring->me].idle_work,
VCN_IDLE_TIMEOUT);
}
int amdgpu_vcn_dec_ring_test_ring(struct amdgpu_ring *ring)
@@ -1485,6 +1483,37 @@ int vcn_set_powergating_state(struct amdgpu_ip_block *ip_block,
return ret;
}
static struct amdgpu_fence *
amdgpu_vcn_ring_reset_begin_helper(struct amdgpu_ring *ring,
struct amdgpu_ring *guilty_ring,
struct amdgpu_fence *timedout_fence)
{
struct amdgpu_fence *fence;
drm_sched_wqueue_stop(&ring->sched);
if (ring == guilty_ring)
fence = timedout_fence;
else
fence = amdgpu_ring_find_guilty_fence(ring);
amdgpu_ring_reset_helper_begin(ring, fence);
return fence;
}
static int
amdgpu_vcn_ring_reset_end_helper(struct amdgpu_ring *ring,
struct amdgpu_fence *fence)
{
int r;
r = amdgpu_ring_reset_helper_end(ring, fence);
if (r)
return r;
drm_sched_wqueue_start(&ring->sched);
return 0;
}
/**
* amdgpu_vcn_ring_reset - Reset a VCN ring
* @ring: ring to reset
@@ -1502,48 +1531,33 @@ int amdgpu_vcn_ring_reset(struct amdgpu_ring *ring,
{
struct amdgpu_device *adev = ring->adev;
struct amdgpu_vcn_inst *vinst = &adev->vcn.inst[ring->me];
struct amdgpu_fence *dec_fence;
struct amdgpu_fence *enc_fence[AMDGPU_VCN_MAX_ENC_RINGS];
int r, i;
if (adev->vcn.inst[ring->me].using_unified_queue)
return -EINVAL;
mutex_lock(&vinst->engine_reset_mutex);
/* Stop the scheduler's work queue for the dec and enc rings if they are running.
* This ensures that no new tasks are submitted to the queues while
* the reset is in progress.
*/
drm_sched_wqueue_stop(&vinst->ring_dec.sched);
dec_fence = amdgpu_vcn_ring_reset_begin_helper(&vinst->ring_dec, ring,
timedout_fence);
for (i = 0; i < vinst->num_enc_rings; i++)
drm_sched_wqueue_stop(&vinst->ring_enc[i].sched);
enc_fence[i] = amdgpu_vcn_ring_reset_begin_helper(&vinst->ring_enc[i], ring,
timedout_fence);
/* Perform the VCN reset for the specified instance */
r = vinst->reset(vinst);
if (r)
goto unlock;
r = amdgpu_ring_test_ring(&vinst->ring_dec);
r = amdgpu_vcn_ring_reset_end_helper(&vinst->ring_dec, dec_fence);
if (r)
goto unlock;
for (i = 0; i < vinst->num_enc_rings; i++) {
r = amdgpu_ring_test_ring(&vinst->ring_enc[i]);
r = amdgpu_vcn_ring_reset_end_helper(&vinst->ring_enc[i], enc_fence[i]);
if (r)
goto unlock;
}
amdgpu_fence_driver_force_completion(&vinst->ring_dec,
(&vinst->ring_dec == ring) ?
&timedout_fence->base : NULL);
for (i = 0; i < vinst->num_enc_rings; i++)
amdgpu_fence_driver_force_completion(&vinst->ring_enc[i],
(&vinst->ring_enc[i] == ring) ?
&timedout_fence->base : NULL);
/* Restart the scheduler's work queue for the dec and enc rings
* if they were stopped by this function. This allows new tasks
* to be submitted to the queues after the reset is complete.
*/
drm_sched_wqueue_start(&vinst->ring_dec.sched);
for (i = 0; i < vinst->num_enc_rings; i++)
drm_sched_wqueue_start(&vinst->ring_enc[i].sched);
unlock:
mutex_unlock(&vinst->engine_reset_mutex);

View File

@@ -368,6 +368,9 @@ struct amdgpu_vcn {
struct mutex workload_profile_mutex;
u32 reg_count;
const struct amdgpu_hwip_reg_entry *reg_list;
bool disable_uq;
bool disable_kq;
};
struct amdgpu_fw_shared_rb_ptrs_struct {

View File

@@ -381,7 +381,8 @@ int amdgpu_xcp_get_inst_details(struct amdgpu_xcp *xcp,
enum AMDGPU_XCP_IP_BLOCK ip,
uint32_t *inst_mask)
{
if (!xcp->valid || !inst_mask || !(xcp->ip[ip].valid))
if (!xcp->valid || !inst_mask || ip >= AMDGPU_XCP_MAX_BLOCKS ||
!(xcp->ip[ip].valid))
return -EINVAL;
*inst_mask = xcp->ip[ip].inst_mask;
@@ -468,14 +469,18 @@ void amdgpu_xcp_release_sched(struct amdgpu_device *adev,
{
struct drm_gpu_scheduler *sched =
container_of(entity->entity.rq, typeof(*sched), rq);
struct amdgpu_xcp_mgr *xcp_mgr = adev->xcp_mgr;
if (!adev->xcp_mgr)
if (!xcp_mgr)
return;
if (drm_sched_wqueue_ready(sched)) {
struct amdgpu_ring *ring = to_amdgpu_ring(sched);
atomic_dec(&adev->xcp_mgr->xcp[ring->xcp_id].ref_cnt);
mutex_lock(&xcp_mgr->xcp_lock);
if (ring->xcp_id < xcp_mgr->num_xcps && xcp_mgr->xcp[ring->xcp_id].valid)
atomic_dec(&xcp_mgr->xcp[ring->xcp_id].ref_cnt);
mutex_unlock(&xcp_mgr->xcp_lock);
}
}
@@ -488,7 +493,9 @@ int amdgpu_xcp_select_scheds(struct amdgpu_device *adev,
u32 sel_xcp_id;
int i;
struct amdgpu_xcp_mgr *xcp_mgr = adev->xcp_mgr;
int r = 0;
mutex_lock(&xcp_mgr->xcp_lock);
if (fpriv->xcp_id == AMDGPU_XCP_NO_PARTITION) {
u32 least_ref_cnt = ~0;
@@ -505,19 +512,27 @@ int amdgpu_xcp_select_scheds(struct amdgpu_device *adev,
}
sel_xcp_id = fpriv->xcp_id;
if (sel_xcp_id >= xcp_mgr->num_xcps || !xcp_mgr->xcp[sel_xcp_id].valid) {
dev_err(adev->dev, "Selected partition #%d is not valid.", sel_xcp_id);
r = -ENODEV;
goto out;
}
if (xcp_mgr->xcp[sel_xcp_id].gpu_sched[hw_ip][hw_prio].num_scheds) {
*num_scheds =
xcp_mgr->xcp[fpriv->xcp_id].gpu_sched[hw_ip][hw_prio].num_scheds;
xcp_mgr->xcp[sel_xcp_id].gpu_sched[hw_ip][hw_prio].num_scheds;
*scheds =
xcp_mgr->xcp[fpriv->xcp_id].gpu_sched[hw_ip][hw_prio].sched;
atomic_inc(&adev->xcp_mgr->xcp[sel_xcp_id].ref_cnt);
xcp_mgr->xcp[sel_xcp_id].gpu_sched[hw_ip][hw_prio].sched;
atomic_inc(&xcp_mgr->xcp[sel_xcp_id].ref_cnt);
dev_dbg(adev->dev, "Selected partition #%d", sel_xcp_id);
} else {
dev_err(adev->dev, "Failed to schedule partition #%d.", sel_xcp_id);
return -ENOENT;
r = -ENOENT;
}
return 0;
out:
mutex_unlock(&xcp_mgr->xcp_lock);
return r;
}
static void amdgpu_set_xcp_id(struct amdgpu_device *adev,
@@ -574,6 +589,9 @@ static void amdgpu_xcp_gpu_sched_update(struct amdgpu_device *adev,
{
unsigned int *num_gpu_sched;
if (sel_xcp_id >= MAX_XCP || sel_xcp_id == AMDGPU_XCP_NO_PARTITION)
return;
num_gpu_sched = &adev->xcp_mgr->xcp[sel_xcp_id]
.gpu_sched[ring->funcs->type][ring->hw_prio].num_scheds;
adev->xcp_mgr->xcp[sel_xcp_id].gpu_sched[ring->funcs->type][ring->hw_prio]
@@ -903,7 +921,7 @@ static void amdgpu_xcp_cfg_sysfs_init(struct amdgpu_device *adev)
{
struct amdgpu_xcp_res_details *xcp_res;
struct amdgpu_xcp_cfg *xcp_cfg;
int i, r, j, rid, mode;
int i, r, rid, mode;
if (!adev->xcp_mgr)
return;
@@ -949,14 +967,16 @@ static void amdgpu_xcp_cfg_sysfs_init(struct amdgpu_device *adev)
&xcp_cfg_res_sysfs_ktype,
&xcp_cfg->kobj, "%s",
xcp_res_names[rid]);
if (r)
if (r) {
kobject_put(&xcp_res->kobj);
goto err;
}
}
adev->xcp_mgr->xcp_cfg = xcp_cfg;
return;
err:
for (j = 0; j < i; j++) {
while (i--) {
xcp_res = &xcp_cfg->xcp_res[i];
kobject_put(&xcp_res->kobj);
}

View File

@@ -106,53 +106,6 @@ static const int walf_pcs_err_noncorrectable_mask_reg_aldebaran[] = {
smnPCS_GOPX1_PCS_ERROR_NONCORRECTABLE_MASK + 0x100000
};
static const int xgmi3x16_pcs_err_status_reg_v6_4[] = {
smnPCS_XGMI3X16_PCS_ERROR_STATUS,
smnPCS_XGMI3X16_PCS_ERROR_STATUS + 0x100000
};
static const int xgmi3x16_pcs_err_noncorrectable_mask_reg_v6_4[] = {
smnPCS_XGMI3X16_PCS_ERROR_NONCORRECTABLE_MASK,
smnPCS_XGMI3X16_PCS_ERROR_NONCORRECTABLE_MASK + 0x100000
};
static const u64 xgmi_v6_4_0_mca_base_array[] = {
0x11a09200,
0x11b09200,
};
static const char *xgmi_v6_4_0_ras_error_code_ext[32] = {
[0x00] = "XGMI PCS DataLossErr",
[0x01] = "XGMI PCS TrainingErr",
[0x02] = "XGMI PCS FlowCtrlAckErr",
[0x03] = "XGMI PCS RxFifoUnderflowErr",
[0x04] = "XGMI PCS RxFifoOverflowErr",
[0x05] = "XGMI PCS CRCErr",
[0x06] = "XGMI PCS BERExceededErr",
[0x07] = "XGMI PCS TxMetaDataErr",
[0x08] = "XGMI PCS ReplayBufParityErr",
[0x09] = "XGMI PCS DataParityErr",
[0x0a] = "XGMI PCS ReplayFifoOverflowErr",
[0x0b] = "XGMI PCS ReplayFifoUnderflowErr",
[0x0c] = "XGMI PCS ElasticFifoOverflowErr",
[0x0d] = "XGMI PCS DeskewErr",
[0x0e] = "XGMI PCS FlowCtrlCRCErr",
[0x0f] = "XGMI PCS DataStartupLimitErr",
[0x10] = "XGMI PCS FCInitTimeoutErr",
[0x11] = "XGMI PCS RecoveryTimeoutErr",
[0x12] = "XGMI PCS ReadySerialTimeoutErr",
[0x13] = "XGMI PCS ReadySerialAttemptErr",
[0x14] = "XGMI PCS RecoveryAttemptErr",
[0x15] = "XGMI PCS RecoveryRelockAttemptErr",
[0x16] = "XGMI PCS ReplayAttemptErr",
[0x17] = "XGMI PCS SyncHdrErr",
[0x18] = "XGMI PCS TxReplayTimeoutErr",
[0x19] = "XGMI PCS RxReplayTimeoutErr",
[0x1a] = "XGMI PCS LinkSubTxTimeoutErr",
[0x1b] = "XGMI PCS LinkSubRxTimeoutErr",
[0x1c] = "XGMI PCS RxCMDPktErr",
};
static const struct amdgpu_pcs_ras_field xgmi_pcs_ras_fields[] = {
{"XGMI PCS DataLossErr",
SOC15_REG_FIELD(XGMI0_PCS_GOPX16_PCS_ERROR_STATUS, DataLossErr)},
@@ -1152,91 +1105,15 @@ int amdgpu_xgmi_remove_device(struct amdgpu_device *adev)
return 0;
}
static int xgmi_v6_4_0_aca_bank_parser(struct aca_handle *handle, struct aca_bank *bank,
enum aca_smu_type type, void *data)
{
struct amdgpu_device *adev = handle->adev;
struct aca_bank_info info;
const char *error_str;
u64 status, count;
int ret, ext_error_code;
ret = aca_bank_info_decode(bank, &info);
if (ret)
return ret;
status = bank->regs[ACA_REG_IDX_STATUS];
ext_error_code = ACA_REG__STATUS__ERRORCODEEXT(status);
error_str = ext_error_code < ARRAY_SIZE(xgmi_v6_4_0_ras_error_code_ext) ?
xgmi_v6_4_0_ras_error_code_ext[ext_error_code] : NULL;
if (error_str)
dev_info(adev->dev, "%s detected\n", error_str);
count = ACA_REG__MISC0__ERRCNT(bank->regs[ACA_REG_IDX_MISC0]);
switch (type) {
case ACA_SMU_TYPE_UE:
if (ext_error_code != 0 && ext_error_code != 1 && ext_error_code != 9)
count = 0ULL;
bank->aca_err_type = ACA_ERROR_TYPE_UE;
ret = aca_error_cache_log_bank_error(handle, &info, ACA_ERROR_TYPE_UE, count);
break;
case ACA_SMU_TYPE_CE:
count = ext_error_code == 6 ? count : 0ULL;
bank->aca_err_type = ACA_ERROR_TYPE_CE;
ret = aca_error_cache_log_bank_error(handle, &info, bank->aca_err_type, count);
break;
default:
return -EINVAL;
}
return ret;
}
static const struct aca_bank_ops xgmi_v6_4_0_aca_bank_ops = {
.aca_bank_parser = xgmi_v6_4_0_aca_bank_parser,
};
static const struct aca_info xgmi_v6_4_0_aca_info = {
.hwip = ACA_HWIP_TYPE_PCS_XGMI,
.mask = ACA_ERROR_UE_MASK | ACA_ERROR_CE_MASK,
.bank_ops = &xgmi_v6_4_0_aca_bank_ops,
};
static int amdgpu_xgmi_ras_late_init(struct amdgpu_device *adev, struct ras_common_if *ras_block)
{
int r;
if (!adev->gmc.xgmi.supported ||
adev->gmc.xgmi.num_physical_nodes == 0)
return 0;
amdgpu_ras_reset_error_count(adev, AMDGPU_RAS_BLOCK__XGMI_WAFL);
r = amdgpu_ras_block_late_init(adev, ras_block);
if (r)
return r;
switch (amdgpu_ip_version(adev, XGMI_HWIP, 0)) {
case IP_VERSION(6, 4, 0):
case IP_VERSION(6, 4, 1):
r = amdgpu_ras_bind_aca(adev, AMDGPU_RAS_BLOCK__XGMI_WAFL,
&xgmi_v6_4_0_aca_info, NULL);
if (r)
goto late_fini;
break;
default:
break;
}
return 0;
late_fini:
amdgpu_ras_block_late_fini(adev, ras_block);
return r;
return amdgpu_ras_block_late_init(adev, ras_block);
}
uint64_t amdgpu_xgmi_get_relative_phy_addr(struct amdgpu_device *adev,
@@ -1252,7 +1129,7 @@ static void pcs_clear_status(struct amdgpu_device *adev, uint32_t pcs_status_reg
WREG32_PCIE(pcs_status_reg, 0);
}
static void amdgpu_xgmi_legacy_reset_ras_error_count(struct amdgpu_device *adev)
static void amdgpu_xgmi_reset_ras_error_count(struct amdgpu_device *adev)
{
uint32_t i;
@@ -1278,54 +1155,6 @@ static void amdgpu_xgmi_legacy_reset_ras_error_count(struct amdgpu_device *adev)
default:
break;
}
switch (amdgpu_ip_version(adev, XGMI_HWIP, 0)) {
case IP_VERSION(6, 4, 0):
case IP_VERSION(6, 4, 1):
for (i = 0; i < ARRAY_SIZE(xgmi3x16_pcs_err_status_reg_v6_4); i++)
pcs_clear_status(adev,
xgmi3x16_pcs_err_status_reg_v6_4[i]);
break;
default:
break;
}
}
static void __xgmi_v6_4_0_reset_error_count(struct amdgpu_device *adev, int xgmi_inst, u64 mca_base)
{
uint64_t smn_base =
amdgpu_reg_get_smn_base64(adev, XGMI_HWIP, xgmi_inst);
WREG64_MCA(smn_base, mca_base, ACA_REG_IDX_STATUS, 0ULL);
}
static void xgmi_v6_4_0_reset_error_count(struct amdgpu_device *adev, int xgmi_inst)
{
int i;
for (i = 0; i < ARRAY_SIZE(xgmi_v6_4_0_mca_base_array); i++)
__xgmi_v6_4_0_reset_error_count(adev, xgmi_inst, xgmi_v6_4_0_mca_base_array[i]);
}
static void xgmi_v6_4_0_reset_ras_error_count(struct amdgpu_device *adev)
{
int i;
for_each_inst(i, adev->aid_mask)
xgmi_v6_4_0_reset_error_count(adev, i);
}
static void amdgpu_xgmi_reset_ras_error_count(struct amdgpu_device *adev)
{
switch (amdgpu_ip_version(adev, XGMI_HWIP, 0)) {
case IP_VERSION(6, 4, 0):
case IP_VERSION(6, 4, 1):
xgmi_v6_4_0_reset_ras_error_count(adev);
break;
default:
amdgpu_xgmi_legacy_reset_ras_error_count(adev);
break;
}
}
static int amdgpu_xgmi_query_pcs_error_status(struct amdgpu_device *adev,
@@ -1343,11 +1172,7 @@ static int amdgpu_xgmi_query_pcs_error_status(struct amdgpu_device *adev,
if (is_xgmi_pcs) {
if (amdgpu_ip_version(adev, XGMI_HWIP, 0) ==
IP_VERSION(6, 1, 0) ||
amdgpu_ip_version(adev, XGMI_HWIP, 0) ==
IP_VERSION(6, 4, 0) ||
amdgpu_ip_version(adev, XGMI_HWIP, 0) ==
IP_VERSION(6, 4, 1)) {
IP_VERSION(6, 1, 0)) {
pcs_ras_fields = &xgmi3x16_pcs_ras_fields[0];
field_array_size = ARRAY_SIZE(xgmi3x16_pcs_ras_fields);
} else {
@@ -1381,11 +1206,11 @@ static int amdgpu_xgmi_query_pcs_error_status(struct amdgpu_device *adev,
return 0;
}
static void amdgpu_xgmi_legacy_query_ras_error_count(struct amdgpu_device *adev,
static void amdgpu_xgmi_query_ras_error_count(struct amdgpu_device *adev,
void *ras_error_status)
{
struct ras_err_data *err_data = (struct ras_err_data *)ras_error_status;
int i, supported = 1;
int i;
uint32_t data, mask_data = 0;
uint32_t ue_cnt = 0, ce_cnt = 0;
@@ -1449,26 +1274,6 @@ static void amdgpu_xgmi_legacy_query_ras_error_count(struct amdgpu_device *adev,
}
break;
default:
supported = 0;
break;
}
switch (amdgpu_ip_version(adev, XGMI_HWIP, 0)) {
case IP_VERSION(6, 4, 0):
case IP_VERSION(6, 4, 1):
/* check xgmi3x16 pcs error */
for (i = 0; i < ARRAY_SIZE(xgmi3x16_pcs_err_status_reg_v6_4); i++) {
data = RREG32_PCIE(xgmi3x16_pcs_err_status_reg_v6_4[i]);
mask_data =
RREG32_PCIE(xgmi3x16_pcs_err_noncorrectable_mask_reg_v6_4[i]);
if (data)
amdgpu_xgmi_query_pcs_error_status(adev, data,
mask_data, &ue_cnt, &ce_cnt, true, true);
}
break;
default:
if (!supported)
dev_warn(adev->dev, "XGMI RAS error query not supported");
break;
}
@@ -1478,90 +1283,6 @@ static void amdgpu_xgmi_legacy_query_ras_error_count(struct amdgpu_device *adev,
err_data->ce_count += ce_cnt;
}
static enum aca_error_type xgmi_v6_4_0_pcs_mca_get_error_type(struct amdgpu_device *adev, u64 status)
{
const char *error_str;
int ext_error_code;
ext_error_code = ACA_REG__STATUS__ERRORCODEEXT(status);
error_str = ext_error_code < ARRAY_SIZE(xgmi_v6_4_0_ras_error_code_ext) ?
xgmi_v6_4_0_ras_error_code_ext[ext_error_code] : NULL;
if (error_str)
dev_info(adev->dev, "%s detected\n", error_str);
switch (ext_error_code) {
case 0:
return ACA_ERROR_TYPE_UE;
case 6:
return ACA_ERROR_TYPE_CE;
default:
return -EINVAL;
}
return -EINVAL;
}
static void __xgmi_v6_4_0_query_error_count(struct amdgpu_device *adev, struct amdgpu_smuio_mcm_config_info *mcm_info,
u64 mca_base, struct ras_err_data *err_data)
{
int xgmi_inst = mcm_info->die_id;
uint64_t smn_base;
u64 status = 0;
status = RREG64_MCA(xgmi_inst, mca_base, ACA_REG_IDX_STATUS);
if (!ACA_REG__STATUS__VAL(status))
return;
switch (xgmi_v6_4_0_pcs_mca_get_error_type(adev, status)) {
case ACA_ERROR_TYPE_UE:
amdgpu_ras_error_statistic_ue_count(err_data, mcm_info, 1ULL);
break;
case ACA_ERROR_TYPE_CE:
amdgpu_ras_error_statistic_ce_count(err_data, mcm_info, 1ULL);
break;
default:
break;
}
smn_base = amdgpu_reg_get_smn_base64(adev, XGMI_HWIP, xgmi_inst);
WREG64_MCA(smn_base, mca_base, ACA_REG_IDX_STATUS, 0ULL);
}
static void xgmi_v6_4_0_query_error_count(struct amdgpu_device *adev, int xgmi_inst, struct ras_err_data *err_data)
{
struct amdgpu_smuio_mcm_config_info mcm_info = {
.socket_id = adev->smuio.funcs->get_socket_id(adev),
.die_id = xgmi_inst,
};
int i;
for (i = 0; i < ARRAY_SIZE(xgmi_v6_4_0_mca_base_array); i++)
__xgmi_v6_4_0_query_error_count(adev, &mcm_info, xgmi_v6_4_0_mca_base_array[i], err_data);
}
static void xgmi_v6_4_0_query_ras_error_count(struct amdgpu_device *adev, void *ras_error_status)
{
struct ras_err_data *err_data = (struct ras_err_data *)ras_error_status;
int i;
for_each_inst(i, adev->aid_mask)
xgmi_v6_4_0_query_error_count(adev, i, err_data);
}
static void amdgpu_xgmi_query_ras_error_count(struct amdgpu_device *adev,
void *ras_error_status)
{
switch (amdgpu_ip_version(adev, XGMI_HWIP, 0)) {
case IP_VERSION(6, 4, 0):
case IP_VERSION(6, 4, 1):
xgmi_v6_4_0_query_ras_error_count(adev, ras_error_status);
break;
default:
amdgpu_xgmi_legacy_query_ras_error_count(adev, ras_error_status);
break;
}
}
/* Trigger XGMI/WAFL error */
static int amdgpu_ras_error_inject_xgmi(struct amdgpu_device *adev,
void *inject_if, uint32_t instance_mask)
@@ -1663,6 +1384,16 @@ static void amdgpu_xgmi_reset_on_init_work(struct work_struct *work)
if (r && r != -EHWPOISON)
dev_err(tmp_adev->dev,
"error during bad page data initialization");
/*
* For the reset-on-init path (e.g. an NPS memory partition
* switch) the RAS IP block hw_init was skipped under the
* minimal init level, so uniras was never enabled. Bring it
* up now that the reset domain has been unlocked. This is a
* no-op for any other reset path where RAS is already
* initialized, and for non-uniras devices.
*/
amdgpu_ras_resume_after_reset(tmp_adev);
}
}

View File

@@ -273,8 +273,10 @@ static int aqua_vanjaram_get_xcp_res_info(struct amdgpu_xcp_mgr *xcp_mgr,
xcp_cfg->num_res = ARRAY_SIZE(max_res);
for (i = 0; i < xcp_cfg->num_res; i++) {
res_lt_xcp = max_res[i] < num_xcp;
xcp_cfg->xcp_res[i].id = i;
if (!max_res[i])
continue;
res_lt_xcp = max_res[i] < num_xcp;
xcp_cfg->xcp_res[i].num_inst =
res_lt_xcp ? 1 : max_res[i] / num_xcp;
xcp_cfg->xcp_res[i].num_inst =
@@ -589,6 +591,29 @@ static struct aqua_reg_list pcie_reg_addrs[] = {
{ smreg_0x1A380088, 6, DW_ADDR_INCR },
};
/*
* Return the GPU's internal US switch port, or NULL if it is not visible
* (e.g. passthrough) or the EP is parented under an unrelated bridge.
*/
static struct pci_dev *aqua_vanjaram_get_us_pdev(struct amdgpu_device *adev)
{
struct pci_dev *ds_pdev, *us_pdev;
ds_pdev = pci_upstream_bridge(adev->pdev);
if (!ds_pdev || ds_pdev->vendor != PCI_VENDOR_ID_ATI ||
pci_pcie_type(ds_pdev) != PCI_EXP_TYPE_DOWNSTREAM)
return NULL;
us_pdev = pci_upstream_bridge(ds_pdev);
if (!us_pdev ||
(us_pdev->vendor != PCI_VENDOR_ID_ATI &&
us_pdev->vendor != PCI_VENDOR_ID_AMD) ||
pci_pcie_type(us_pdev) != PCI_EXP_TYPE_UPSTREAM)
return NULL;
return us_pdev;
}
static ssize_t aqua_vanjaram_read_pcie_state(struct amdgpu_device *adev,
void *buf, size_t max_size)
{
@@ -596,7 +621,7 @@ static ssize_t aqua_vanjaram_read_pcie_state(struct amdgpu_device *adev,
uint32_t start_addr, incrx, num_regs, szbuf;
struct amdgpu_regs_pcie_v1_0 *pcie_regs;
struct amdgpu_smn_reg_data *reg_data;
struct pci_dev *us_pdev, *ds_pdev;
struct pci_dev *us_pdev;
int aer_cap, r, n;
if (!buf || !max_size)
@@ -628,25 +653,27 @@ static ssize_t aqua_vanjaram_read_pcie_state(struct amdgpu_device *adev,
}
}
ds_pdev = pci_upstream_bridge(adev->pdev);
us_pdev = pci_upstream_bridge(ds_pdev);
us_pdev = aqua_vanjaram_get_us_pdev(adev);
if (us_pdev) {
pcie_capability_read_word(us_pdev, PCI_EXP_DEVSTA,
&pcie_regs->device_status);
pcie_capability_read_word(us_pdev, PCI_EXP_LNKSTA,
&pcie_regs->link_status);
pcie_capability_read_word(us_pdev, PCI_EXP_DEVSTA,
&pcie_regs->device_status);
pcie_capability_read_word(us_pdev, PCI_EXP_LNKSTA,
&pcie_regs->link_status);
aer_cap = pci_find_ext_capability(us_pdev, PCI_EXT_CAP_ID_ERR);
if (aer_cap) {
pci_read_config_dword(us_pdev,
aer_cap + PCI_ERR_COR_STATUS,
&pcie_regs->pcie_corr_err_status);
pci_read_config_dword(us_pdev,
aer_cap + PCI_ERR_UNCOR_STATUS,
&pcie_regs->pcie_uncorr_err_status);
}
aer_cap = pci_find_ext_capability(us_pdev, PCI_EXT_CAP_ID_ERR);
if (aer_cap) {
pci_read_config_dword(us_pdev, aer_cap + PCI_ERR_COR_STATUS,
&pcie_regs->pcie_corr_err_status);
pci_read_config_dword(us_pdev, aer_cap + PCI_ERR_UNCOR_STATUS,
&pcie_regs->pcie_uncorr_err_status);
pci_read_config_dword(us_pdev, PCI_PRIMARY_BUS,
&pcie_regs->sub_bus_number_latency);
}
pci_read_config_dword(us_pdev, PCI_PRIMARY_BUS,
&pcie_regs->sub_bus_number_latency);
pcie_reg_state->common_header.structure_size = szbuf;
pcie_reg_state->common_header.format_revision = 1;
pcie_reg_state->common_header.content_revision = 0;

View File

@@ -114,8 +114,10 @@ static uint32_t atom_iio_execute(struct atom_context *ctx, int base,
uint32_t index, uint32_t data)
{
uint32_t temp = 0xCDCDCDCD;
int start = base;
while (1)
/* IIO opcodes read up to base+3; keep within the BIOS image */
while (base + 3 < ctx->bios_size)
switch (CU8(base)) {
case ATOM_IIO_NOP:
base++;
@@ -180,6 +182,9 @@ static uint32_t atom_iio_execute(struct atom_context *ctx, int base,
pr_info("Unknown IIO opcode\n");
return 0;
}
pr_info("IIO method starting at offset %d runs past BIOS image\n", start);
return 0;
}
static uint32_t atom_get_src_int(atom_exec_context *ctx, uint8_t attr,
@@ -1327,11 +1332,25 @@ static void atom_index_iio(struct atom_context *ctx, int base)
ctx->iio = kzalloc(2 * 256, GFP_KERNEL);
if (!ctx->iio)
return;
while (CU8(base) == ATOM_IIO_START) {
ctx->iio[CU8(base + 1)] = base + 2;
while (base + 1 < ctx->bios_size && CU8(base) == ATOM_IIO_START) {
uint8_t index = CU8(base + 1);
int start = base + 2;
base += 2;
while (CU8(base) != ATOM_IIO_END)
base += atom_iio_len[CU8(base)];
while (base < ctx->bios_size && CU8(base) != ATOM_IIO_END) {
uint8_t op = CU8(base);
/*
* Unknown opcode: its length is unknown so the byte
* stream cannot be resynced reliably.
*/
if (op >= ARRAY_SIZE(atom_iio_len))
return;
base += atom_iio_len[op];
}
if (base >= ctx->bios_size)
return;
/* Only index well-formed methods, others stay 0 */
ctx->iio[index] = start;
base += 3;
}
}
@@ -1339,6 +1358,7 @@ static void atom_index_iio(struct atom_context *ctx, int base)
static void atom_get_vbios_name(struct atom_context *ctx)
{
unsigned char *p_rom;
unsigned char *p_end;
unsigned char str_num;
unsigned short off_to_vbios_str;
unsigned char *c_ptr;
@@ -1349,39 +1369,48 @@ static void atom_get_vbios_name(struct atom_context *ctx)
char *back;
p_rom = ctx->bios;
p_end = p_rom + ctx->bios_size;
if (p_rom + OFFSET_TO_GET_ATOMBIOS_STRING_START + 1 >= p_end)
goto no_name;
str_num = *(p_rom + OFFSET_TO_GET_ATOMBIOS_NUMBER_OF_STRINGS);
if (str_num != 0) {
off_to_vbios_str =
*(unsigned short *)(p_rom + OFFSET_TO_GET_ATOMBIOS_STRING_START);
if (!str_num)
goto no_name;
c_ptr = (unsigned char *)(p_rom + off_to_vbios_str);
} else {
/* do not know where to find name */
memcpy(ctx->name, na, 7);
ctx->name[7] = 0;
return;
}
off_to_vbios_str =
*(unsigned short *)(p_rom + OFFSET_TO_GET_ATOMBIOS_STRING_START);
c_ptr = (unsigned char *)(p_rom + off_to_vbios_str);
if (c_ptr >= p_end)
goto no_name;
/*
* skip the atombios strings, usually 4
* 1st is P/N, 2nd is ASIC, 3rd is PCI type, 4th is Memory type
*/
for (i = 0; i < str_num; i++) {
while (*c_ptr != 0)
while (c_ptr < p_end && *c_ptr != 0)
c_ptr++;
c_ptr++;
}
/* skip the following 2 chars: 0x0D 0x0A */
c_ptr += 2;
if (c_ptr >= p_end)
goto no_name;
name_size = strnlen(c_ptr, STRLEN_LONG - 1);
name_size = strnlen(c_ptr, min(STRLEN_LONG - 1, (int)(p_end - c_ptr)));
memcpy(ctx->name, c_ptr, name_size);
back = ctx->name + name_size;
while ((*--back) == ' ')
;
*(back + 1) = '\0';
return;
no_name:
/* do not know where to find name */
strscpy(ctx->name, na, sizeof(ctx->name));
}
static void atom_get_vbios_date(struct atom_context *ctx)
@@ -1553,7 +1582,7 @@ static inline void atom_print_vbios_info(struct atom_context *ctx)
drm_info(ctx->card->dev, "ATOM BIOS: %s\n", vbios_info);
}
struct atom_context *amdgpu_atom_parse(struct card_info *card, void *bios)
struct atom_context *amdgpu_atom_parse(struct card_info *card, void *bios, uint32_t bios_size)
{
int base;
struct atom_context *ctx =
@@ -1567,6 +1596,7 @@ struct atom_context *amdgpu_atom_parse(struct card_info *card, void *bios)
ctx->card = card;
ctx->bios = bios;
ctx->bios_size = bios_size;
if (CU16(0) != ATOM_BIOS_MAGIC) {
pr_info("Invalid BIOS magic\n");

View File

@@ -133,6 +133,7 @@ struct atom_context {
struct card_info *card;
struct mutex mutex;
void *bios;
uint32_t bios_size;
uint32_t cmd_table, data_table;
uint16_t *iio;
@@ -160,7 +161,7 @@ struct atom_context {
extern int amdgpu_atom_debug;
struct atom_context *amdgpu_atom_parse(struct card_info *card, void *bios);
struct atom_context *amdgpu_atom_parse(struct card_info *card, void *bios, uint32_t bios_size);
int amdgpu_atom_execute_table(struct atom_context *ctx, int index, uint32_t *params, int params_size);
int amdgpu_atom_asic_init(struct atom_context *ctx);
void amdgpu_atom_destroy(struct atom_context *ctx);

View File

@@ -1876,12 +1876,6 @@ static void cik_invalidate_hdp(struct amdgpu_device *adev,
}
}
static bool cik_need_full_reset(struct amdgpu_device *adev)
{
/* change this when we support soft reset */
return true;
}
static void cik_get_pcie_usage(struct amdgpu_device *adev, uint64_t *count0,
uint64_t *count1)
{
@@ -1971,7 +1965,6 @@ static const struct amdgpu_asic_funcs cik_asic_funcs =
.get_config_memsize = &cik_get_config_memsize,
.flush_hdp = &cik_flush_hdp,
.invalidate_hdp = &cik_invalidate_hdp,
.need_full_reset = &cik_need_full_reset,
.init_doorbell_index = &legacy_doorbell_index_init,
.get_pcie_usage = &cik_get_pcie_usage,
.need_reset_on_init = &cik_need_reset_on_init,

View File

@@ -410,36 +410,6 @@ static u32 dce_v10_0_hpd_get_gpio_reg(struct amdgpu_device *adev)
return mmDC_GPIO_HPD_A;
}
static bool dce_v10_0_is_display_hung(struct amdgpu_device *adev)
{
u32 crtc_hung = 0;
u32 crtc_status[6];
u32 i, j, tmp;
for (i = 0; i < adev->mode_info.num_crtc; i++) {
tmp = RREG32(mmCRTC_CONTROL + crtc_offsets[i]);
if (REG_GET_FIELD(tmp, CRTC_CONTROL, CRTC_MASTER_EN)) {
crtc_status[i] = RREG32(mmCRTC_STATUS_HV_COUNT + crtc_offsets[i]);
crtc_hung |= (1 << i);
}
}
for (j = 0; j < 10; j++) {
for (i = 0; i < adev->mode_info.num_crtc; i++) {
if (crtc_hung & (1 << i)) {
tmp = RREG32(mmCRTC_STATUS_HV_COUNT + crtc_offsets[i]);
if (tmp != crtc_status[i])
crtc_hung &= ~(1 << i);
}
}
if (crtc_hung == 0)
return false;
udelay(100);
}
return true;
}
static void dce_v10_0_set_vga_render_state(struct amdgpu_device *adev,
bool render)
{
@@ -2956,40 +2926,6 @@ static bool dce_v10_0_is_idle(struct amdgpu_ip_block *ip_block)
return true;
}
static bool dce_v10_0_check_soft_reset(struct amdgpu_ip_block *ip_block)
{
struct amdgpu_device *adev = ip_block->adev;
return dce_v10_0_is_display_hung(adev);
}
static int dce_v10_0_soft_reset(struct amdgpu_ip_block *ip_block)
{
u32 srbm_soft_reset = 0, tmp;
struct amdgpu_device *adev = ip_block->adev;
if (dce_v10_0_is_display_hung(adev))
srbm_soft_reset |= SRBM_SOFT_RESET__SOFT_RESET_DC_MASK;
if (srbm_soft_reset) {
tmp = RREG32(mmSRBM_SOFT_RESET);
tmp |= srbm_soft_reset;
dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp);
WREG32(mmSRBM_SOFT_RESET, tmp);
tmp = RREG32(mmSRBM_SOFT_RESET);
udelay(50);
tmp &= ~srbm_soft_reset;
WREG32(mmSRBM_SOFT_RESET, tmp);
tmp = RREG32(mmSRBM_SOFT_RESET);
/* Wait a little for things to settle down */
udelay(50);
}
return 0;
}
static void dce_v10_0_set_crtc_vblank_interrupt_state(struct amdgpu_device *adev,
int crtc,
enum amdgpu_interrupt_state state)
@@ -3332,8 +3268,6 @@ static const struct amd_ip_funcs dce_v10_0_ip_funcs = {
.suspend = dce_v10_0_suspend,
.resume = dce_v10_0_resume,
.is_idle = dce_v10_0_is_idle,
.check_soft_reset = dce_v10_0_check_soft_reset,
.soft_reset = dce_v10_0_soft_reset,
.set_clockgating_state = dce_v10_0_set_clockgating_state,
.set_powergating_state = dce_v10_0_set_powergating_state,
};

View File

@@ -378,35 +378,6 @@ static u32 dce_v6_0_hpd_get_gpio_reg(struct amdgpu_device *adev)
return mmDC_GPIO_HPD_A;
}
static bool dce_v6_0_is_display_hung(struct amdgpu_device *adev)
{
u32 crtc_hung = 0;
u32 crtc_status[6];
u32 i, j, tmp;
for (i = 0; i < adev->mode_info.num_crtc; i++) {
if (RREG32(mmCRTC_CONTROL + crtc_offsets[i]) & CRTC_CONTROL__CRTC_MASTER_EN_MASK) {
crtc_status[i] = RREG32(mmCRTC_STATUS_HV_COUNT + crtc_offsets[i]);
crtc_hung |= (1 << i);
}
}
for (j = 0; j < 10; j++) {
for (i = 0; i < adev->mode_info.num_crtc; i++) {
if (crtc_hung & (1 << i)) {
tmp = RREG32(mmCRTC_STATUS_HV_COUNT + crtc_offsets[i]);
if (tmp != crtc_status[i])
crtc_hung &= ~(1 << i);
}
}
if (crtc_hung == 0)
return false;
udelay(100);
}
return true;
}
static void dce_v6_0_set_vga_render_state(struct amdgpu_device *adev,
bool render)
{
@@ -2901,33 +2872,6 @@ static bool dce_v6_0_is_idle(struct amdgpu_ip_block *ip_block)
return true;
}
static int dce_v6_0_soft_reset(struct amdgpu_ip_block *ip_block)
{
u32 srbm_soft_reset = 0, tmp;
struct amdgpu_device *adev = ip_block->adev;
if (dce_v6_0_is_display_hung(adev))
srbm_soft_reset |= SRBM_SOFT_RESET__SOFT_RESET_DC_MASK;
if (srbm_soft_reset) {
tmp = RREG32(mmSRBM_SOFT_RESET);
tmp |= srbm_soft_reset;
dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp);
WREG32(mmSRBM_SOFT_RESET, tmp);
tmp = RREG32(mmSRBM_SOFT_RESET);
udelay(50);
tmp &= ~srbm_soft_reset;
WREG32(mmSRBM_SOFT_RESET, tmp);
tmp = RREG32(mmSRBM_SOFT_RESET);
/* Wait a little for things to settle down */
udelay(50);
}
return 0;
}
static void dce_v6_0_set_crtc_vblank_interrupt_state(struct amdgpu_device *adev,
int crtc,
enum amdgpu_interrupt_state state)
@@ -3224,7 +3168,6 @@ static const struct amd_ip_funcs dce_v6_0_ip_funcs = {
.suspend = dce_v6_0_suspend,
.resume = dce_v6_0_resume,
.is_idle = dce_v6_0_is_idle,
.soft_reset = dce_v6_0_soft_reset,
.set_clockgating_state = dce_v6_0_set_clockgating_state,
.set_powergating_state = dce_v6_0_set_powergating_state,
};

View File

@@ -362,35 +362,6 @@ static u32 dce_v8_0_hpd_get_gpio_reg(struct amdgpu_device *adev)
return mmDC_GPIO_HPD_A;
}
static bool dce_v8_0_is_display_hung(struct amdgpu_device *adev)
{
u32 crtc_hung = 0;
u32 crtc_status[6];
u32 i, j, tmp;
for (i = 0; i < adev->mode_info.num_crtc; i++) {
if (RREG32(mmCRTC_CONTROL + crtc_offsets[i]) & CRTC_CONTROL__CRTC_MASTER_EN_MASK) {
crtc_status[i] = RREG32(mmCRTC_STATUS_HV_COUNT + crtc_offsets[i]);
crtc_hung |= (1 << i);
}
}
for (j = 0; j < 10; j++) {
for (i = 0; i < adev->mode_info.num_crtc; i++) {
if (crtc_hung & (1 << i)) {
tmp = RREG32(mmCRTC_STATUS_HV_COUNT + crtc_offsets[i]);
if (tmp != crtc_status[i])
crtc_hung &= ~(1 << i);
}
}
if (crtc_hung == 0)
return false;
udelay(100);
}
return true;
}
static void dce_v8_0_set_vga_render_state(struct amdgpu_device *adev,
bool render)
{
@@ -2873,33 +2844,6 @@ static bool dce_v8_0_is_idle(struct amdgpu_ip_block *ip_block)
return true;
}
static int dce_v8_0_soft_reset(struct amdgpu_ip_block *ip_block)
{
u32 srbm_soft_reset = 0, tmp;
struct amdgpu_device *adev = ip_block->adev;
if (dce_v8_0_is_display_hung(adev))
srbm_soft_reset |= SRBM_SOFT_RESET__SOFT_RESET_DC_MASK;
if (srbm_soft_reset) {
tmp = RREG32(mmSRBM_SOFT_RESET);
tmp |= srbm_soft_reset;
dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp);
WREG32(mmSRBM_SOFT_RESET, tmp);
tmp = RREG32(mmSRBM_SOFT_RESET);
udelay(50);
tmp &= ~srbm_soft_reset;
WREG32(mmSRBM_SOFT_RESET, tmp);
tmp = RREG32(mmSRBM_SOFT_RESET);
/* Wait a little for things to settle down */
udelay(50);
}
return 0;
}
static void dce_v8_0_set_crtc_vblank_interrupt_state(struct amdgpu_device *adev,
int crtc,
enum amdgpu_interrupt_state state)
@@ -3241,7 +3185,6 @@ static const struct amd_ip_funcs dce_v8_0_ip_funcs = {
.suspend = dce_v8_0_suspend,
.resume = dce_v8_0_resume,
.is_idle = dce_v8_0_is_idle,
.soft_reset = dce_v8_0_soft_reset,
.set_clockgating_state = dce_v8_0_set_clockgating_state,
.set_powergating_state = dce_v8_0_set_powergating_state,
};

View File

@@ -7852,6 +7852,8 @@ static int gfx_v10_0_early_init(struct amdgpu_ip_block *ip_block)
/* init rlcg reg access ctrl */
gfx_v10_0_init_rlcg_reg_access_ctrl(adev);
amdgpu_init_rlc_reg_funcs(adev);
return gfx_v10_0_init_microcode(adev);
}

View File

@@ -1923,6 +1923,11 @@ static int gfx_v11_0_sw_init(struct amdgpu_ip_block *ip_block)
if (r)
return r;
adev->gfx.me.use_mmio_for_reset = false;
adev->gfx.mec.use_mmio_for_reset = true;
mutex_init(&adev->gfx.mec.reset_mutex);
return 0;
}
@@ -4233,13 +4238,13 @@ static int gfx_v11_0_gfx_mqd_init(struct amdgpu_device *adev, void *m,
return 0;
}
static int gfx_v11_0_kgq_init_queue(struct amdgpu_ring *ring, bool reset)
static int gfx_v11_0_kgq_init_queue(struct amdgpu_ring *ring)
{
struct amdgpu_device *adev = ring->adev;
struct v11_gfx_mqd *mqd = ring->mqd_ptr;
int mqd_idx = ring - &adev->gfx.gfx_ring[0];
if (!reset && !amdgpu_in_reset(adev) && !adev->in_suspend) {
if (!amdgpu_in_reset(adev) && !adev->in_suspend) {
memset((void *)mqd, 0, sizeof(*mqd));
mutex_lock(&adev->srbm_mutex);
soc21_grbm_select(adev, ring->me, ring->pipe, ring->queue, 0);
@@ -4266,7 +4271,7 @@ static int gfx_v11_0_cp_async_gfx_ring_resume(struct amdgpu_device *adev)
int r, i;
for (i = 0; i < adev->gfx.num_gfx_rings; i++) {
r = gfx_v11_0_kgq_init_queue(&adev->gfx.gfx_ring[i], false);
r = gfx_v11_0_kgq_init_queue(&adev->gfx.gfx_ring[i]);
if (r)
return r;
}
@@ -4603,13 +4608,13 @@ static int gfx_v11_0_kiq_init_queue(struct amdgpu_ring *ring)
return 0;
}
static int gfx_v11_0_kcq_init_queue(struct amdgpu_ring *ring, bool reset)
static int gfx_v11_0_kcq_init_queue(struct amdgpu_ring *ring)
{
struct amdgpu_device *adev = ring->adev;
struct v11_compute_mqd *mqd = ring->mqd_ptr;
int mqd_idx = ring - &adev->gfx.compute_ring[0];
if (!reset && !amdgpu_in_reset(adev) && !adev->in_suspend) {
if (!amdgpu_in_reset(adev) && !adev->in_suspend) {
memset((void *)mqd, 0, sizeof(*mqd));
mutex_lock(&adev->srbm_mutex);
soc21_grbm_select(adev, ring->me, ring->pipe, ring->queue, 0);
@@ -4646,7 +4651,7 @@ static int gfx_v11_0_kcq_resume(struct amdgpu_device *adev)
gfx_v11_0_cp_compute_enable(adev, true);
for (i = 0; i < adev->gfx.num_compute_rings; i++) {
r = gfx_v11_0_kcq_init_queue(&adev->gfx.compute_ring[i], false);
r = gfx_v11_0_kcq_init_queue(&adev->gfx.compute_ring[i]);
if (r)
return r;
}
@@ -5265,38 +5270,12 @@ static int gfx_v11_0_soft_reset(struct amdgpu_ip_block *ip_block)
amdgpu_gfx_rlc_exit_safe_mode(adev, 0);
return gfx_v11_0_cp_resume(adev);
}
r = gfx_v11_0_cp_resume(adev);
if (r)
return r;
static bool gfx_v11_0_check_soft_reset(struct amdgpu_ip_block *ip_block)
{
int i, r;
struct amdgpu_device *adev = ip_block->adev;
struct amdgpu_ring *ring;
long tmo = msecs_to_jiffies(1000);
for (i = 0; i < adev->gfx.num_gfx_rings; i++) {
ring = &adev->gfx.gfx_ring[i];
r = amdgpu_ring_test_ib(ring, tmo);
if (r)
return true;
}
for (i = 0; i < adev->gfx.num_compute_rings; i++) {
ring = &adev->gfx.compute_ring[i];
r = amdgpu_ring_test_ib(ring, tmo);
if (r)
return true;
}
return false;
}
static int gfx_v11_0_post_soft_reset(struct amdgpu_ip_block *ip_block)
{
struct amdgpu_device *adev = ip_block->adev;
/**
* GFX soft reset will impact MES, need resume MES when do GFX soft reset
* GFX soft reset impacts MES, resume MES after GFX soft reset is finished
*/
return amdgpu_mes_resume(adev, 0);
}
@@ -5420,6 +5399,8 @@ static int gfx_v11_0_early_init(struct amdgpu_ip_block *ip_block)
gfx_v11_0_init_rlcg_reg_access_ctrl(adev);
amdgpu_init_rlc_reg_funcs(adev);
return gfx_v11_0_init_microcode(adev);
}
@@ -6708,22 +6689,29 @@ static int gfx_v11_0_set_priv_inst_fault_state(struct amdgpu_device *adev,
static void gfx_v11_0_handle_priv_fault(struct amdgpu_device *adev,
struct amdgpu_iv_entry *entry)
{
u8 me_id, pipe_id, queue_id;
struct amdgpu_ring *ring;
int i;
me_id = (entry->ring_id & 0x0c) >> 2;
pipe_id = (entry->ring_id & 0x03) >> 0;
queue_id = (entry->ring_id & 0x70) >> 4;
u32 doorbell_offset = entry->src_data[0] & AMDGPU_CTXID0_DOORBELL_ID_MASK;
/*
* Try KQ first by ring_id (HW slot is authoritative). The
* KMD compute_hqd_mask contract guarantees KCQ and user queues
* never share a HW slot.
*/
if (!adev->gfx.disable_kq) {
u8 me_id = (entry->ring_id & 0x0c) >> 2;
u8 pipe_id = (entry->ring_id & 0x03) >> 0;
u8 queue_id = (entry->ring_id & 0x70) >> 4;
struct amdgpu_ring *ring;
int i;
switch (me_id) {
case 0:
for (i = 0; i < adev->gfx.num_gfx_rings; i++) {
ring = &adev->gfx.gfx_ring[i];
if (ring->me == me_id && ring->pipe == pipe_id &&
ring->queue == queue_id)
ring->queue == queue_id) {
drm_sched_fault(&ring->sched);
return;
}
}
break;
case 1:
@@ -6731,8 +6719,10 @@ static void gfx_v11_0_handle_priv_fault(struct amdgpu_device *adev,
for (i = 0; i < adev->gfx.num_compute_rings; i++) {
ring = &adev->gfx.compute_ring[i];
if (ring->me == me_id && ring->pipe == pipe_id &&
ring->queue == queue_id)
ring->queue == queue_id) {
drm_sched_fault(&ring->sched);
return;
}
}
break;
default:
@@ -6740,6 +6730,11 @@ static void gfx_v11_0_handle_priv_fault(struct amdgpu_device *adev,
break;
}
}
/* No KQ matched: HW slot is a MES-scheduled user queue. */
if (adev->enable_mes && doorbell_offset)
amdgpu_userq_process_reset_irq(adev, entry->pasid,
doorbell_offset);
}
static int gfx_v11_0_priv_reg_irq(struct amdgpu_device *adev,
@@ -6846,233 +6841,14 @@ static void gfx_v11_0_emit_mem_sync(struct amdgpu_ring *ring)
amdgpu_ring_write(ring, gcr_cntl); /* GCR_CNTL */
}
static bool gfx_v11_pipe_reset_support(struct amdgpu_device *adev)
{
/* Disable the pipe reset until the CPFW fully support it.*/
dev_warn_once(adev->dev, "The CPFW hasn't support pipe reset yet.\n");
return false;
}
static int gfx_v11_reset_gfx_pipe(struct amdgpu_ring *ring)
{
struct amdgpu_device *adev = ring->adev;
uint32_t reset_pipe = 0, clean_pipe = 0;
int r;
if (!gfx_v11_pipe_reset_support(adev))
return -EOPNOTSUPP;
gfx_v11_0_set_safe_mode(adev, 0);
mutex_lock(&adev->srbm_mutex);
soc21_grbm_select(adev, ring->me, ring->pipe, ring->queue, 0);
switch (ring->pipe) {
case 0:
reset_pipe = REG_SET_FIELD(reset_pipe, CP_ME_CNTL,
PFP_PIPE0_RESET, 1);
reset_pipe = REG_SET_FIELD(reset_pipe, CP_ME_CNTL,
ME_PIPE0_RESET, 1);
clean_pipe = REG_SET_FIELD(clean_pipe, CP_ME_CNTL,
PFP_PIPE0_RESET, 0);
clean_pipe = REG_SET_FIELD(clean_pipe, CP_ME_CNTL,
ME_PIPE0_RESET, 0);
break;
case 1:
reset_pipe = REG_SET_FIELD(reset_pipe, CP_ME_CNTL,
PFP_PIPE1_RESET, 1);
reset_pipe = REG_SET_FIELD(reset_pipe, CP_ME_CNTL,
ME_PIPE1_RESET, 1);
clean_pipe = REG_SET_FIELD(clean_pipe, CP_ME_CNTL,
PFP_PIPE1_RESET, 0);
clean_pipe = REG_SET_FIELD(clean_pipe, CP_ME_CNTL,
ME_PIPE1_RESET, 0);
break;
default:
break;
}
WREG32_SOC15(GC, 0, regCP_ME_CNTL, reset_pipe);
WREG32_SOC15(GC, 0, regCP_ME_CNTL, clean_pipe);
r = (RREG32(SOC15_REG_OFFSET(GC, 0, regCP_GFX_RS64_INSTR_PNTR1)) << 2) -
RS64_FW_UC_START_ADDR_LO;
soc21_grbm_select(adev, 0, 0, 0, 0);
mutex_unlock(&adev->srbm_mutex);
gfx_v11_0_unset_safe_mode(adev, 0);
dev_info(adev->dev, "The ring %s pipe reset to the ME firmware start PC: %s\n", ring->name,
r == 0 ? "successfully" : "failed");
/* FIXME: Sometimes driver can't cache the ME firmware start PC correctly,
* so the pipe reset status relies on the later gfx ring test result.
*/
return 0;
}
static int gfx_v11_0_reset_kgq(struct amdgpu_ring *ring,
unsigned int vmid,
struct amdgpu_fence *timedout_fence)
{
struct amdgpu_device *adev = ring->adev;
bool use_mmio = false;
int r;
bool use_mmio = adev->gfx.me.use_mmio_for_reset;
amdgpu_ring_reset_helper_begin(ring, timedout_fence);
r = amdgpu_mes_reset_legacy_queue(ring->adev, ring, vmid, use_mmio, 0);
if (r) {
dev_warn(adev->dev, "reset via MES failed and try pipe reset %d\n", r);
r = gfx_v11_reset_gfx_pipe(ring);
if (r)
return r;
}
if (use_mmio) {
r = gfx_v11_0_kgq_init_queue(ring, true);
if (r) {
dev_err(adev->dev, "failed to init kgq\n");
return r;
}
r = amdgpu_mes_map_legacy_queue(adev, ring, 0);
if (r) {
dev_err(adev->dev, "failed to remap kgq\n");
return r;
}
}
return amdgpu_ring_reset_helper_end(ring, timedout_fence);
}
static int gfx_v11_0_reset_compute_pipe(struct amdgpu_ring *ring)
{
struct amdgpu_device *adev = ring->adev;
uint32_t reset_pipe = 0, clean_pipe = 0;
int r;
if (!gfx_v11_pipe_reset_support(adev))
return -EOPNOTSUPP;
gfx_v11_0_set_safe_mode(adev, 0);
mutex_lock(&adev->srbm_mutex);
soc21_grbm_select(adev, ring->me, ring->pipe, ring->queue, 0);
reset_pipe = RREG32_SOC15(GC, 0, regCP_MEC_RS64_CNTL);
clean_pipe = reset_pipe;
if (adev->gfx.rs64_enable) {
switch (ring->pipe) {
case 0:
reset_pipe = REG_SET_FIELD(reset_pipe, CP_MEC_RS64_CNTL,
MEC_PIPE0_RESET, 1);
clean_pipe = REG_SET_FIELD(clean_pipe, CP_MEC_RS64_CNTL,
MEC_PIPE0_RESET, 0);
break;
case 1:
reset_pipe = REG_SET_FIELD(reset_pipe, CP_MEC_RS64_CNTL,
MEC_PIPE1_RESET, 1);
clean_pipe = REG_SET_FIELD(clean_pipe, CP_MEC_RS64_CNTL,
MEC_PIPE1_RESET, 0);
break;
case 2:
reset_pipe = REG_SET_FIELD(reset_pipe, CP_MEC_RS64_CNTL,
MEC_PIPE2_RESET, 1);
clean_pipe = REG_SET_FIELD(clean_pipe, CP_MEC_RS64_CNTL,
MEC_PIPE2_RESET, 0);
break;
case 3:
reset_pipe = REG_SET_FIELD(reset_pipe, CP_MEC_RS64_CNTL,
MEC_PIPE3_RESET, 1);
clean_pipe = REG_SET_FIELD(clean_pipe, CP_MEC_RS64_CNTL,
MEC_PIPE3_RESET, 0);
break;
default:
break;
}
WREG32_SOC15(GC, 0, regCP_MEC_RS64_CNTL, reset_pipe);
WREG32_SOC15(GC, 0, regCP_MEC_RS64_CNTL, clean_pipe);
r = (RREG32_SOC15(GC, 0, regCP_MEC_RS64_INSTR_PNTR) << 2) -
RS64_FW_UC_START_ADDR_LO;
} else {
if (ring->me == 1) {
switch (ring->pipe) {
case 0:
reset_pipe = REG_SET_FIELD(reset_pipe, CP_MEC_CNTL,
MEC_ME1_PIPE0_RESET, 1);
clean_pipe = REG_SET_FIELD(clean_pipe, CP_MEC_CNTL,
MEC_ME1_PIPE0_RESET, 0);
break;
case 1:
reset_pipe = REG_SET_FIELD(reset_pipe, CP_MEC_CNTL,
MEC_ME1_PIPE1_RESET, 1);
clean_pipe = REG_SET_FIELD(clean_pipe, CP_MEC_CNTL,
MEC_ME1_PIPE1_RESET, 0);
break;
case 2:
reset_pipe = REG_SET_FIELD(reset_pipe, CP_MEC_CNTL,
MEC_ME1_PIPE2_RESET, 1);
clean_pipe = REG_SET_FIELD(clean_pipe, CP_MEC_CNTL,
MEC_ME1_PIPE2_RESET, 0);
break;
case 3:
reset_pipe = REG_SET_FIELD(reset_pipe, CP_MEC_CNTL,
MEC_ME1_PIPE3_RESET, 1);
clean_pipe = REG_SET_FIELD(clean_pipe, CP_MEC_CNTL,
MEC_ME1_PIPE3_RESET, 0);
break;
default:
break;
}
/* mec1 fw pc: CP_MEC1_INSTR_PNTR */
} else {
switch (ring->pipe) {
case 0:
reset_pipe = REG_SET_FIELD(reset_pipe, CP_MEC_CNTL,
MEC_ME2_PIPE0_RESET, 1);
clean_pipe = REG_SET_FIELD(clean_pipe, CP_MEC_CNTL,
MEC_ME2_PIPE0_RESET, 0);
break;
case 1:
reset_pipe = REG_SET_FIELD(reset_pipe, CP_MEC_CNTL,
MEC_ME2_PIPE1_RESET, 1);
clean_pipe = REG_SET_FIELD(clean_pipe, CP_MEC_CNTL,
MEC_ME2_PIPE1_RESET, 0);
break;
case 2:
reset_pipe = REG_SET_FIELD(reset_pipe, CP_MEC_CNTL,
MEC_ME2_PIPE2_RESET, 1);
clean_pipe = REG_SET_FIELD(clean_pipe, CP_MEC_CNTL,
MEC_ME2_PIPE2_RESET, 0);
break;
case 3:
reset_pipe = REG_SET_FIELD(reset_pipe, CP_MEC_CNTL,
MEC_ME2_PIPE3_RESET, 1);
clean_pipe = REG_SET_FIELD(clean_pipe, CP_MEC_CNTL,
MEC_ME2_PIPE3_RESET, 0);
break;
default:
break;
}
/* mec2 fw pc: CP:CP_MEC2_INSTR_PNTR */
}
WREG32_SOC15(GC, 0, regCP_MEC_CNTL, reset_pipe);
WREG32_SOC15(GC, 0, regCP_MEC_CNTL, clean_pipe);
r = RREG32(SOC15_REG_OFFSET(GC, 0, regCP_MEC1_INSTR_PNTR));
}
soc21_grbm_select(adev, 0, 0, 0, 0);
mutex_unlock(&adev->srbm_mutex);
gfx_v11_0_unset_safe_mode(adev, 0);
dev_info(adev->dev, "The ring %s pipe resets to MEC FW start PC: %s\n", ring->name,
r == 0 ? "successfully" : "failed");
/*FIXME:Sometimes driver can't cache the MEC firmware start PC correctly, so the pipe
* reset status relies on the compute ring test result.
*/
return 0;
return amdgpu_gfx_mes_reset_queue(ring, vmid, timedout_fence, use_mmio);
}
static int gfx_v11_0_reset_kcq(struct amdgpu_ring *ring,
@@ -7080,30 +6856,8 @@ static int gfx_v11_0_reset_kcq(struct amdgpu_ring *ring,
struct amdgpu_fence *timedout_fence)
{
struct amdgpu_device *adev = ring->adev;
int r = 0;
amdgpu_ring_reset_helper_begin(ring, timedout_fence);
r = amdgpu_mes_reset_legacy_queue(ring->adev, ring, vmid, true, 0);
if (r) {
dev_warn(adev->dev, "fail(%d) to reset kcq and try pipe reset\n", r);
r = gfx_v11_0_reset_compute_pipe(ring);
if (r)
return r;
}
r = gfx_v11_0_kcq_init_queue(ring, true);
if (r) {
dev_err(adev->dev, "fail to init kcq\n");
return r;
}
r = amdgpu_mes_map_legacy_queue(adev, ring, 0);
if (r) {
dev_err(adev->dev, "failed to remap kcq\n");
return r;
}
return amdgpu_ring_reset_helper_end(ring, timedout_fence);
return amdgpu_gfx_reset_mes_compute(adev, ring, timedout_fence, NULL, NULL, NULL);
}
static void gfx_v11_ip_print(struct amdgpu_ip_block *ip_block, struct drm_printer *p)
@@ -7281,8 +7035,6 @@ static const struct amd_ip_funcs gfx_v11_0_ip_funcs = {
.is_idle = gfx_v11_0_is_idle,
.wait_for_idle = gfx_v11_0_wait_for_idle,
.soft_reset = gfx_v11_0_soft_reset,
.check_soft_reset = gfx_v11_0_check_soft_reset,
.post_soft_reset = gfx_v11_0_post_soft_reset,
.set_clockgating_state = gfx_v11_0_set_clockgating_state,
.set_powergating_state = gfx_v11_0_set_powergating_state,
.get_clockgating_state = gfx_v11_0_get_clockgating_state,

View File

@@ -1603,6 +1603,11 @@ static int gfx_v12_0_sw_init(struct amdgpu_ip_block *ip_block)
if (r)
return r;
adev->gfx.me.use_mmio_for_reset = false;
adev->gfx.mec.use_mmio_for_reset = true;
mutex_init(&adev->gfx.mec.reset_mutex);
return 0;
}
@@ -3071,13 +3076,13 @@ static int gfx_v12_0_gfx_mqd_init(struct amdgpu_device *adev, void *m,
return 0;
}
static int gfx_v12_0_kgq_init_queue(struct amdgpu_ring *ring, bool reset)
static int gfx_v12_0_kgq_init_queue(struct amdgpu_ring *ring)
{
struct amdgpu_device *adev = ring->adev;
struct v12_gfx_mqd *mqd = ring->mqd_ptr;
int mqd_idx = ring - &adev->gfx.gfx_ring[0];
if (!reset && !amdgpu_in_reset(adev) && !adev->in_suspend) {
if (!amdgpu_in_reset(adev) && !adev->in_suspend) {
memset((void *)mqd, 0, sizeof(*mqd));
mutex_lock(&adev->srbm_mutex);
soc24_grbm_select(adev, ring->me, ring->pipe, ring->queue, 0);
@@ -3104,7 +3109,7 @@ static int gfx_v12_0_cp_async_gfx_ring_resume(struct amdgpu_device *adev)
int i, r;
for (i = 0; i < adev->gfx.num_gfx_rings; i++) {
r = gfx_v12_0_kgq_init_queue(&adev->gfx.gfx_ring[i], false);
r = gfx_v12_0_kgq_init_queue(&adev->gfx.gfx_ring[i]);
if (r)
return r;
}
@@ -3441,13 +3446,13 @@ static int gfx_v12_0_kiq_init_queue(struct amdgpu_ring *ring)
return 0;
}
static int gfx_v12_0_kcq_init_queue(struct amdgpu_ring *ring, bool reset)
static int gfx_v12_0_kcq_init_queue(struct amdgpu_ring *ring)
{
struct amdgpu_device *adev = ring->adev;
struct v12_compute_mqd *mqd = ring->mqd_ptr;
int mqd_idx = ring - &adev->gfx.compute_ring[0];
if (!reset && !amdgpu_in_reset(adev) && !adev->in_suspend) {
if (!amdgpu_in_reset(adev) && !adev->in_suspend) {
memset((void *)mqd, 0, sizeof(*mqd));
mutex_lock(&adev->srbm_mutex);
soc24_grbm_select(adev, ring->me, ring->pipe, ring->queue, 0);
@@ -3485,7 +3490,7 @@ static int gfx_v12_0_kcq_resume(struct amdgpu_device *adev)
gfx_v12_0_cp_compute_enable(adev, true);
for (i = 0; i < adev->gfx.num_compute_rings; i++) {
r = gfx_v12_0_kcq_init_queue(&adev->gfx.compute_ring[i], false);
r = gfx_v12_0_kcq_init_queue(&adev->gfx.compute_ring[i]);
if (r)
return r;
}
@@ -3986,6 +3991,8 @@ static int gfx_v12_0_early_init(struct amdgpu_ip_block *ip_block)
gfx_v12_0_init_rlcg_reg_access_ctrl(adev);
amdgpu_init_rlc_reg_funcs(adev);
return gfx_v12_0_init_microcode(adev);
}
@@ -5025,22 +5032,30 @@ static int gfx_v12_0_set_priv_inst_fault_state(struct amdgpu_device *adev,
static void gfx_v12_0_handle_priv_fault(struct amdgpu_device *adev,
struct amdgpu_iv_entry *entry)
{
u8 me_id, pipe_id, queue_id;
struct amdgpu_ring *ring;
int i;
me_id = (entry->ring_id & 0x0c) >> 2;
pipe_id = (entry->ring_id & 0x03) >> 0;
queue_id = (entry->ring_id & 0x70) >> 4;
u32 doorbell_offset = entry->src_data[0] & AMDGPU_CTXID0_DOORBELL_ID_MASK;
/*
* Try KQ first by ring_id; UQ as fallback. KCQ and UQ never share
* a HW slot (compute_hqd_mask contract).
*/
if (!adev->gfx.disable_kq) {
u8 me_id, pipe_id, queue_id;
struct amdgpu_ring *ring;
int i;
me_id = (entry->ring_id & 0x0c) >> 2;
pipe_id = (entry->ring_id & 0x03) >> 0;
queue_id = (entry->ring_id & 0x70) >> 4;
switch (me_id) {
case 0:
for (i = 0; i < adev->gfx.num_gfx_rings; i++) {
ring = &adev->gfx.gfx_ring[i];
if (ring->me == me_id && ring->pipe == pipe_id &&
ring->queue == queue_id)
ring->queue == queue_id) {
drm_sched_fault(&ring->sched);
return;
}
}
break;
case 1:
@@ -5048,8 +5063,10 @@ static void gfx_v12_0_handle_priv_fault(struct amdgpu_device *adev,
for (i = 0; i < adev->gfx.num_compute_rings; i++) {
ring = &adev->gfx.compute_ring[i];
if (ring->me == me_id && ring->pipe == pipe_id &&
ring->queue == queue_id)
ring->queue == queue_id) {
drm_sched_fault(&ring->sched);
return;
}
}
break;
default:
@@ -5057,6 +5074,11 @@ static void gfx_v12_0_handle_priv_fault(struct amdgpu_device *adev,
break;
}
}
/* No KQ matched: HW slot is a MES-scheduled user queue. */
if (adev->enable_mes && doorbell_offset)
amdgpu_userq_process_reset_irq(adev, entry->pasid,
doorbell_offset);
}
static int gfx_v12_0_priv_reg_irq(struct amdgpu_device *adev,
@@ -5261,185 +5283,14 @@ static void gfx_v12_ip_dump(struct amdgpu_ip_block *ip_block)
amdgpu_gfx_off_ctrl(adev, true);
}
static bool gfx_v12_pipe_reset_support(struct amdgpu_device *adev)
{
/* Disable the pipe reset until the CPFW fully support it.*/
dev_warn_once(adev->dev, "The CPFW hasn't support pipe reset yet.\n");
return false;
}
static int gfx_v12_reset_gfx_pipe(struct amdgpu_ring *ring)
{
struct amdgpu_device *adev = ring->adev;
uint32_t reset_pipe = 0, clean_pipe = 0;
int r;
if (!gfx_v12_pipe_reset_support(adev))
return -EOPNOTSUPP;
gfx_v12_0_set_safe_mode(adev, 0);
mutex_lock(&adev->srbm_mutex);
soc24_grbm_select(adev, ring->me, ring->pipe, ring->queue, 0);
switch (ring->pipe) {
case 0:
reset_pipe = REG_SET_FIELD(reset_pipe, CP_ME_CNTL,
PFP_PIPE0_RESET, 1);
reset_pipe = REG_SET_FIELD(reset_pipe, CP_ME_CNTL,
ME_PIPE0_RESET, 1);
clean_pipe = REG_SET_FIELD(clean_pipe, CP_ME_CNTL,
PFP_PIPE0_RESET, 0);
clean_pipe = REG_SET_FIELD(clean_pipe, CP_ME_CNTL,
ME_PIPE0_RESET, 0);
break;
case 1:
reset_pipe = REG_SET_FIELD(reset_pipe, CP_ME_CNTL,
PFP_PIPE1_RESET, 1);
reset_pipe = REG_SET_FIELD(reset_pipe, CP_ME_CNTL,
ME_PIPE1_RESET, 1);
clean_pipe = REG_SET_FIELD(clean_pipe, CP_ME_CNTL,
PFP_PIPE1_RESET, 0);
clean_pipe = REG_SET_FIELD(clean_pipe, CP_ME_CNTL,
ME_PIPE1_RESET, 0);
break;
default:
break;
}
WREG32_SOC15(GC, 0, regCP_ME_CNTL, reset_pipe);
WREG32_SOC15(GC, 0, regCP_ME_CNTL, clean_pipe);
r = (RREG32(SOC15_REG_OFFSET(GC, 0, regCP_GFX_RS64_INSTR_PNTR1)) << 2) -
RS64_FW_UC_START_ADDR_LO;
soc24_grbm_select(adev, 0, 0, 0, 0);
mutex_unlock(&adev->srbm_mutex);
gfx_v12_0_unset_safe_mode(adev, 0);
dev_info(adev->dev, "The ring %s pipe reset: %s\n", ring->name,
r == 0 ? "successfully" : "failed");
/* Sometimes the ME start pc counter can't cache correctly, so the
* PC check only as a reference and pipe reset result rely on the
* later ring test.
*/
return 0;
}
static int gfx_v12_0_reset_kgq(struct amdgpu_ring *ring,
unsigned int vmid,
struct amdgpu_fence *timedout_fence)
{
struct amdgpu_device *adev = ring->adev;
bool use_mmio = false;
int r;
bool use_mmio = adev->gfx.me.use_mmio_for_reset;
amdgpu_ring_reset_helper_begin(ring, timedout_fence);
r = amdgpu_mes_reset_legacy_queue(ring->adev, ring, vmid, use_mmio, 0);
if (r) {
dev_warn(adev->dev, "reset via MES failed and try pipe reset %d\n", r);
r = gfx_v12_reset_gfx_pipe(ring);
if (r)
return r;
}
if (use_mmio) {
r = gfx_v12_0_kgq_init_queue(ring, true);
if (r) {
dev_err(adev->dev, "failed to init kgq\n");
return r;
}
r = amdgpu_mes_map_legacy_queue(adev, ring, 0);
if (r) {
dev_err(adev->dev, "failed to remap kgq\n");
return r;
}
}
return amdgpu_ring_reset_helper_end(ring, timedout_fence);
}
static int gfx_v12_0_reset_compute_pipe(struct amdgpu_ring *ring)
{
struct amdgpu_device *adev = ring->adev;
uint32_t reset_pipe = 0, clean_pipe = 0;
int r = 0;
if (!gfx_v12_pipe_reset_support(adev))
return -EOPNOTSUPP;
gfx_v12_0_set_safe_mode(adev, 0);
mutex_lock(&adev->srbm_mutex);
soc24_grbm_select(adev, ring->me, ring->pipe, ring->queue, 0);
reset_pipe = RREG32_SOC15(GC, 0, regCP_MEC_RS64_CNTL);
clean_pipe = reset_pipe;
if (adev->gfx.rs64_enable) {
switch (ring->pipe) {
case 0:
reset_pipe = REG_SET_FIELD(reset_pipe, CP_MEC_RS64_CNTL,
MEC_PIPE0_RESET, 1);
clean_pipe = REG_SET_FIELD(clean_pipe, CP_MEC_RS64_CNTL,
MEC_PIPE0_RESET, 0);
break;
case 1:
reset_pipe = REG_SET_FIELD(reset_pipe, CP_MEC_RS64_CNTL,
MEC_PIPE1_RESET, 1);
clean_pipe = REG_SET_FIELD(clean_pipe, CP_MEC_RS64_CNTL,
MEC_PIPE1_RESET, 0);
break;
case 2:
reset_pipe = REG_SET_FIELD(reset_pipe, CP_MEC_RS64_CNTL,
MEC_PIPE2_RESET, 1);
clean_pipe = REG_SET_FIELD(clean_pipe, CP_MEC_RS64_CNTL,
MEC_PIPE2_RESET, 0);
break;
case 3:
reset_pipe = REG_SET_FIELD(reset_pipe, CP_MEC_RS64_CNTL,
MEC_PIPE3_RESET, 1);
clean_pipe = REG_SET_FIELD(clean_pipe, CP_MEC_RS64_CNTL,
MEC_PIPE3_RESET, 0);
break;
default:
break;
}
WREG32_SOC15(GC, 0, regCP_MEC_RS64_CNTL, reset_pipe);
WREG32_SOC15(GC, 0, regCP_MEC_RS64_CNTL, clean_pipe);
r = (RREG32_SOC15(GC, 0, regCP_MEC_RS64_INSTR_PNTR) << 2) -
RS64_FW_UC_START_ADDR_LO;
} else {
switch (ring->pipe) {
case 0:
reset_pipe = REG_SET_FIELD(reset_pipe, CP_MEC_CNTL,
MEC_ME1_PIPE0_RESET, 1);
clean_pipe = REG_SET_FIELD(clean_pipe, CP_MEC_CNTL,
MEC_ME1_PIPE0_RESET, 0);
break;
case 1:
reset_pipe = REG_SET_FIELD(reset_pipe, CP_MEC_CNTL,
MEC_ME1_PIPE1_RESET, 1);
clean_pipe = REG_SET_FIELD(clean_pipe, CP_MEC_CNTL,
MEC_ME1_PIPE1_RESET, 0);
break;
default:
break;
}
WREG32_SOC15(GC, 0, regCP_MEC_CNTL, reset_pipe);
WREG32_SOC15(GC, 0, regCP_MEC_CNTL, clean_pipe);
/* Doesn't find the F32 MEC instruction pointer register, and suppose
* the driver won't run into the F32 mode.
*/
}
soc24_grbm_select(adev, 0, 0, 0, 0);
mutex_unlock(&adev->srbm_mutex);
gfx_v12_0_unset_safe_mode(adev, 0);
dev_info(adev->dev, "The ring %s pipe resets: %s\n", ring->name,
r == 0 ? "successfully" : "failed");
/* Need the ring test to verify the pipe reset result.*/
return 0;
return amdgpu_gfx_mes_reset_queue(ring, vmid, timedout_fence, use_mmio);
}
static int gfx_v12_0_reset_kcq(struct amdgpu_ring *ring,
@@ -5447,30 +5298,8 @@ static int gfx_v12_0_reset_kcq(struct amdgpu_ring *ring,
struct amdgpu_fence *timedout_fence)
{
struct amdgpu_device *adev = ring->adev;
int r;
amdgpu_ring_reset_helper_begin(ring, timedout_fence);
r = amdgpu_mes_reset_legacy_queue(ring->adev, ring, vmid, true, 0);
if (r) {
dev_warn(adev->dev, "fail(%d) to reset kcq and try pipe reset\n", r);
r = gfx_v12_0_reset_compute_pipe(ring);
if (r)
return r;
}
r = gfx_v12_0_kcq_init_queue(ring, true);
if (r) {
dev_err(adev->dev, "failed to init kcq\n");
return r;
}
r = amdgpu_mes_map_legacy_queue(adev, ring, 0);
if (r) {
dev_err(adev->dev, "failed to remap kcq\n");
return r;
}
return amdgpu_ring_reset_helper_end(ring, timedout_fence);
return amdgpu_gfx_reset_mes_compute(adev, ring, timedout_fence, NULL, NULL, NULL);
}
static void gfx_v12_0_ring_begin_use(struct amdgpu_ring *ring)

View File

@@ -1287,6 +1287,8 @@ static int gfx_v12_1_sw_init(struct amdgpu_ip_block *ip_block)
if (r)
return r;
mutex_init(&adev->gfx.mec.reset_mutex);
return 0;
}
@@ -3004,6 +3006,8 @@ static int gfx_v12_1_early_init(struct amdgpu_ip_block *ip_block)
gfx_v12_1_init_rlcg_reg_access_ctrl(adev);
amdgpu_init_rlc_reg_funcs(adev);
return gfx_v12_1_init_microcode(adev);
}

View File

@@ -1487,7 +1487,14 @@ static int gfx_v8_0_do_edc_gpr_workarounds(struct amdgpu_device *adev)
/* bail if the compute ring is not ready */
if (!ring->sched.ready)
return 0;
return -EBUSY;
if (amdgpu_in_reset(adev)) {
/* Set preempt condition to execute IB */
amdgpu_ring_set_preempt_cond_exec(ring, true);
/* Flush HDP cache so the GPU can see the updated COND_EXEC value */
amdgpu_device_flush_hdp(adev, NULL);
}
tmp = RREG32(mmGB_EDC_MODE);
WREG32(mmGB_EDC_MODE, 0);
@@ -2028,6 +2035,11 @@ static int gfx_v8_0_sw_init(struct amdgpu_ip_block *ip_block)
adev->gfx.compute_supported_reset =
amdgpu_get_soft_full_reset_mask(&adev->gfx.compute_ring[0]);
if (!amdgpu_sriov_vf(adev) && !adev->debug_disable_ip_block_soft_reset) {
adev->gfx.compute_supported_reset |= AMDGPU_RESET_TYPE_IP_BLOCK_SOFT_RESET;
adev->gfx.gfx_supported_reset |= AMDGPU_RESET_TYPE_IP_BLOCK_SOFT_RESET;
}
return 0;
}
@@ -4703,12 +4715,14 @@ static int gfx_v8_0_cp_test_all_rings(struct amdgpu_device *adev)
if (r)
return r;
r = 0;
for (i = 0; i < adev->gfx.num_compute_rings; i++) {
ring = &adev->gfx.compute_ring[i];
amdgpu_ring_test_helper(ring);
r |= amdgpu_ring_test_helper(ring);
}
return 0;
return r;
}
static int gfx_v8_0_cp_resume(struct amdgpu_device *adev)
@@ -4868,14 +4882,12 @@ static int gfx_v8_0_hw_fini(struct amdgpu_ip_block *ip_block)
}
amdgpu_gfx_rlc_enter_safe_mode(adev, 0);
if (!gfx_v8_0_wait_for_idle(ip_block))
gfx_v8_0_cp_enable(adev, false);
else
if (!amdgpu_in_reset(adev) && gfx_v8_0_wait_for_idle(ip_block))
pr_err("cp is busy, skip halt cp\n");
if (!gfx_v8_0_wait_for_rlc_idle(adev))
adev->gfx.rlc.funcs->stop(adev);
else
pr_err("rlc is busy, skip halt rlc\n");
if (!amdgpu_in_reset(adev) && gfx_v8_0_wait_for_rlc_idle(adev))
pr_err("rlc is busy\n");
gfx_v8_0_cp_enable(adev, false);
adev->gfx.rlc.funcs->stop(adev);
amdgpu_gfx_rlc_exit_safe_mode(adev, 0);
return 0;
@@ -4891,128 +4903,49 @@ static int gfx_v8_0_resume(struct amdgpu_ip_block *ip_block)
return gfx_v8_0_hw_init(ip_block);
}
static bool gfx_v8_0_check_soft_reset(struct amdgpu_ip_block *ip_block)
{
struct amdgpu_device *adev = ip_block->adev;
u32 grbm_soft_reset = 0, srbm_soft_reset = 0;
u32 tmp;
/* GRBM_STATUS */
tmp = RREG32(mmGRBM_STATUS);
if (tmp & (GRBM_STATUS__PA_BUSY_MASK | GRBM_STATUS__SC_BUSY_MASK |
GRBM_STATUS__BCI_BUSY_MASK | GRBM_STATUS__SX_BUSY_MASK |
GRBM_STATUS__TA_BUSY_MASK | GRBM_STATUS__VGT_BUSY_MASK |
GRBM_STATUS__DB_BUSY_MASK | GRBM_STATUS__CB_BUSY_MASK |
GRBM_STATUS__GDS_BUSY_MASK | GRBM_STATUS__SPI_BUSY_MASK |
GRBM_STATUS__IA_BUSY_MASK | GRBM_STATUS__IA_BUSY_NO_DMA_MASK |
GRBM_STATUS__CP_BUSY_MASK | GRBM_STATUS__CP_COHERENCY_BUSY_MASK)) {
grbm_soft_reset = REG_SET_FIELD(grbm_soft_reset,
GRBM_SOFT_RESET, SOFT_RESET_CP, 1);
grbm_soft_reset = REG_SET_FIELD(grbm_soft_reset,
GRBM_SOFT_RESET, SOFT_RESET_GFX, 1);
srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset,
SRBM_SOFT_RESET, SOFT_RESET_GRBM, 1);
}
/* GRBM_STATUS2 */
tmp = RREG32(mmGRBM_STATUS2);
if (REG_GET_FIELD(tmp, GRBM_STATUS2, RLC_BUSY))
grbm_soft_reset = REG_SET_FIELD(grbm_soft_reset,
GRBM_SOFT_RESET, SOFT_RESET_RLC, 1);
if (REG_GET_FIELD(tmp, GRBM_STATUS2, CPF_BUSY) ||
REG_GET_FIELD(tmp, GRBM_STATUS2, CPC_BUSY) ||
REG_GET_FIELD(tmp, GRBM_STATUS2, CPG_BUSY)) {
grbm_soft_reset = REG_SET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET,
SOFT_RESET_CPF, 1);
grbm_soft_reset = REG_SET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET,
SOFT_RESET_CPC, 1);
grbm_soft_reset = REG_SET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET,
SOFT_RESET_CPG, 1);
srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET,
SOFT_RESET_GRBM, 1);
}
/* SRBM_STATUS */
tmp = RREG32(mmSRBM_STATUS);
if (REG_GET_FIELD(tmp, SRBM_STATUS, GRBM_RQ_PENDING))
srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset,
SRBM_SOFT_RESET, SOFT_RESET_GRBM, 1);
if (REG_GET_FIELD(tmp, SRBM_STATUS, SEM_BUSY))
srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset,
SRBM_SOFT_RESET, SOFT_RESET_SEM, 1);
if (grbm_soft_reset || srbm_soft_reset) {
adev->gfx.grbm_soft_reset = grbm_soft_reset;
adev->gfx.srbm_soft_reset = srbm_soft_reset;
return true;
} else {
adev->gfx.grbm_soft_reset = 0;
adev->gfx.srbm_soft_reset = 0;
return false;
}
}
static int gfx_v8_0_pre_soft_reset(struct amdgpu_ip_block *ip_block)
{
struct amdgpu_device *adev = ip_block->adev;
u32 grbm_soft_reset = 0;
if ((!adev->gfx.grbm_soft_reset) &&
(!adev->gfx.srbm_soft_reset))
return 0;
grbm_soft_reset = adev->gfx.grbm_soft_reset;
/* stop the rlc */
adev->gfx.rlc.funcs->stop(adev);
if (REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_CP) ||
REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_GFX))
/* Disable GFX parsing/prefetching */
gfx_v8_0_cp_gfx_enable(adev, false);
if (REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_CP) ||
REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_CPF) ||
REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_CPC) ||
REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_CPG)) {
int i;
for (i = 0; i < adev->gfx.num_compute_rings; i++) {
struct amdgpu_ring *ring = &adev->gfx.compute_ring[i];
mutex_lock(&adev->srbm_mutex);
vi_srbm_select(adev, ring->me, ring->pipe, ring->queue, 0);
gfx_v8_0_deactivate_hqd(adev, 2);
vi_srbm_select(adev, 0, 0, 0, 0);
mutex_unlock(&adev->srbm_mutex);
}
/* Disable MEC parsing/prefetching */
gfx_v8_0_cp_compute_enable(adev, false);
}
return 0;
}
static int gfx_v8_0_soft_reset(struct amdgpu_ip_block *ip_block)
{
struct amdgpu_device *adev = ip_block->adev;
u32 grbm_soft_reset = 0, srbm_soft_reset = 0;
u32 tmp;
int i;
int r;
if ((!adev->gfx.grbm_soft_reset) &&
(!adev->gfx.srbm_soft_reset))
return 0;
grbm_soft_reset =
REG_SET_FIELD(0, GRBM_SOFT_RESET, SOFT_RESET_RLC, 1) |
REG_SET_FIELD(0, GRBM_SOFT_RESET, SOFT_RESET_GFX, 1) |
REG_SET_FIELD(0, GRBM_SOFT_RESET, SOFT_RESET_CP, 1) |
REG_SET_FIELD(0, GRBM_SOFT_RESET, SOFT_RESET_CPF, 1) |
REG_SET_FIELD(0, GRBM_SOFT_RESET, SOFT_RESET_CPC, 1) |
REG_SET_FIELD(0, GRBM_SOFT_RESET, SOFT_RESET_CPG, 1);
grbm_soft_reset = adev->gfx.grbm_soft_reset;
srbm_soft_reset = adev->gfx.srbm_soft_reset;
srbm_soft_reset =
REG_SET_FIELD(0, SRBM_SOFT_RESET, SOFT_RESET_GRBM, 1) |
REG_SET_FIELD(0, SRBM_SOFT_RESET, SOFT_RESET_SEM, 1);
for (i = 0; i < adev->gfx.num_compute_rings; i++) {
struct amdgpu_ring *ring = &adev->gfx.compute_ring[i];
mutex_lock(&adev->srbm_mutex);
vi_srbm_select(adev, ring->me, ring->pipe, ring->queue, 0);
gfx_v8_0_deactivate_hqd(adev, 2);
vi_srbm_select(adev, 0, 0, 0, 0);
mutex_unlock(&adev->srbm_mutex);
udelay(50);
}
ip_block->version->funcs->set_clockgating_state(ip_block, AMD_CG_STATE_UNGATE);
ip_block->version->funcs->set_powergating_state(ip_block, AMD_PG_STATE_UNGATE);
ip_block->version->funcs->suspend(ip_block);
if (grbm_soft_reset || srbm_soft_reset) {
tmp = RREG32(mmGMCON_DEBUG);
tmp = REG_SET_FIELD(tmp, GMCON_DEBUG, GFX_STALL, 1);
tmp = REG_SET_FIELD(tmp, GMCON_DEBUG, GFX_CLEAR, 1);
WREG32(mmGMCON_DEBUG, tmp);
udelay(50);
udelay(100);
}
if (grbm_soft_reset) {
@@ -5022,11 +4955,13 @@ static int gfx_v8_0_soft_reset(struct amdgpu_ip_block *ip_block)
WREG32(mmGRBM_SOFT_RESET, tmp);
tmp = RREG32(mmGRBM_SOFT_RESET);
udelay(50);
udelay(100);
tmp &= ~grbm_soft_reset;
WREG32(mmGRBM_SOFT_RESET, tmp);
tmp = RREG32(mmGRBM_SOFT_RESET);
udelay(100);
}
if (srbm_soft_reset) {
@@ -5036,11 +4971,13 @@ static int gfx_v8_0_soft_reset(struct amdgpu_ip_block *ip_block)
WREG32(mmSRBM_SOFT_RESET, tmp);
tmp = RREG32(mmSRBM_SOFT_RESET);
udelay(50);
udelay(100);
tmp &= ~srbm_soft_reset;
WREG32(mmSRBM_SOFT_RESET, tmp);
tmp = RREG32(mmSRBM_SOFT_RESET);
udelay(100);
}
if (grbm_soft_reset || srbm_soft_reset) {
@@ -5051,48 +4988,15 @@ static int gfx_v8_0_soft_reset(struct amdgpu_ip_block *ip_block)
}
/* Wait a little for things to settle down */
udelay(50);
udelay(100);
return 0;
}
r = ip_block->version->funcs->resume(ip_block);
r |= ip_block->version->funcs->late_init(ip_block);
if (r)
return r;
static int gfx_v8_0_post_soft_reset(struct amdgpu_ip_block *ip_block)
{
struct amdgpu_device *adev = ip_block->adev;
u32 grbm_soft_reset = 0;
if ((!adev->gfx.grbm_soft_reset) &&
(!adev->gfx.srbm_soft_reset))
return 0;
grbm_soft_reset = adev->gfx.grbm_soft_reset;
if (REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_CP) ||
REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_CPF) ||
REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_CPC) ||
REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_CPG)) {
int i;
for (i = 0; i < adev->gfx.num_compute_rings; i++) {
struct amdgpu_ring *ring = &adev->gfx.compute_ring[i];
mutex_lock(&adev->srbm_mutex);
vi_srbm_select(adev, ring->me, ring->pipe, ring->queue, 0);
gfx_v8_0_deactivate_hqd(adev, 2);
vi_srbm_select(adev, 0, 0, 0, 0);
mutex_unlock(&adev->srbm_mutex);
}
gfx_v8_0_kiq_resume(adev);
gfx_v8_0_kcq_resume(adev);
}
if (REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_CP) ||
REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_GFX))
gfx_v8_0_cp_gfx_resume(adev);
gfx_v8_0_cp_test_all_rings(adev);
adev->gfx.rlc.funcs->start(adev);
ip_block->version->funcs->set_clockgating_state(ip_block, AMD_CG_STATE_GATE);
ip_block->version->funcs->set_powergating_state(ip_block, AMD_PG_STATE_GATE);
return 0;
}
@@ -6859,10 +6763,7 @@ static const struct amd_ip_funcs gfx_v8_0_ip_funcs = {
.resume = gfx_v8_0_resume,
.is_idle = gfx_v8_0_is_idle,
.wait_for_idle = gfx_v8_0_wait_for_idle,
.check_soft_reset = gfx_v8_0_check_soft_reset,
.pre_soft_reset = gfx_v8_0_pre_soft_reset,
.soft_reset = gfx_v8_0_soft_reset,
.post_soft_reset = gfx_v8_0_post_soft_reset,
.set_clockgating_state = gfx_v8_0_set_clockgating_state,
.set_powergating_state = gfx_v8_0_set_powergating_state,
.get_clockgating_state = gfx_v8_0_get_clockgating_state,
@@ -6923,10 +6824,12 @@ static const struct amdgpu_ring_funcs gfx_v8_0_ring_funcs_compute = {
.get_wptr = gfx_v8_0_ring_get_wptr_compute,
.set_wptr = gfx_v8_0_ring_set_wptr_compute,
.emit_frame_size =
5 + /* gfx_v8_0_ring_emit_init_cond_exec (from amdgpu_ib_schedule) */
20 + /* gfx_v8_0_ring_emit_gds_switch */
7 + /* gfx_v8_0_ring_emit_hdp_flush */
5 + /* hdp_invalidate */
7 + /* gfx_v8_0_ring_emit_pipeline_sync */
5 + /* gfx_v8_0_ring_emit_init_cond_exec (from amdgpu_vm_flush) */
VI_FLUSH_GPU_TLB_NUM_WREG * 5 + 7 + /* gfx_v8_0_ring_emit_vm_flush */
7 + 7 + 7 + /* gfx_v8_0_ring_emit_fence_compute x3 for user fence, vm fence */
7 + /* gfx_v8_0_emit_mem_sync_compute */
@@ -6947,6 +6850,7 @@ static const struct amdgpu_ring_funcs gfx_v8_0_ring_funcs_compute = {
.soft_recovery = gfx_v8_0_ring_soft_recovery,
.emit_mem_sync = gfx_v8_0_emit_mem_sync_compute,
.emit_wave_limit = gfx_v8_0_emit_wave_limit,
.init_cond_exec = gfx_v8_0_ring_emit_init_cond_exec,
};
static const struct amdgpu_ring_funcs gfx_v8_0_ring_funcs_kiq = {

View File

@@ -4875,6 +4875,8 @@ static int gfx_v9_0_early_init(struct amdgpu_ip_block *ip_block)
/* init rlcg reg access ctrl */
gfx_v9_0_init_rlcg_reg_access_ctrl(adev);
amdgpu_init_rlc_reg_funcs(adev);
return gfx_v9_0_init_microcode(adev);
}

File diff suppressed because it is too large Load Diff

View File

@@ -167,44 +167,6 @@ static void gmc_v8_0_init_golden_registers(struct amdgpu_device *adev)
}
}
static void gmc_v8_0_mc_stop(struct amdgpu_device *adev)
{
u32 blackout;
struct amdgpu_ip_block *ip_block;
ip_block = amdgpu_device_ip_get_ip_block(adev, AMD_IP_BLOCK_TYPE_GMC);
if (!ip_block)
return;
gmc_v8_0_wait_for_idle(ip_block);
blackout = RREG32(mmMC_SHARED_BLACKOUT_CNTL);
if (REG_GET_FIELD(blackout, MC_SHARED_BLACKOUT_CNTL, BLACKOUT_MODE) != 1) {
/* Block CPU access */
WREG32(mmBIF_FB_EN, 0);
/* blackout the MC */
blackout = REG_SET_FIELD(blackout,
MC_SHARED_BLACKOUT_CNTL, BLACKOUT_MODE, 1);
WREG32(mmMC_SHARED_BLACKOUT_CNTL, blackout);
}
/* wait for the MC to settle */
udelay(100);
}
static void gmc_v8_0_mc_resume(struct amdgpu_device *adev)
{
u32 tmp;
/* unblackout the MC */
tmp = RREG32(mmMC_SHARED_BLACKOUT_CNTL);
tmp = REG_SET_FIELD(tmp, MC_SHARED_BLACKOUT_CNTL, BLACKOUT_MODE, 0);
WREG32(mmMC_SHARED_BLACKOUT_CNTL, tmp);
/* allow CPU access */
tmp = REG_SET_FIELD(0, BIF_FB_EN, FB_READ_EN, 1);
tmp = REG_SET_FIELD(tmp, BIF_FB_EN, FB_WRITE_EN, 1);
WREG32(mmBIF_FB_EN, tmp);
}
/**
* gmc_v8_0_init_microcode - load ucode images from disk
*
@@ -1293,89 +1255,6 @@ static int gmc_v8_0_wait_for_idle(struct amdgpu_ip_block *ip_block)
}
static bool gmc_v8_0_check_soft_reset(struct amdgpu_ip_block *ip_block)
{
u32 srbm_soft_reset = 0;
struct amdgpu_device *adev = ip_block->adev;
u32 tmp = RREG32(mmSRBM_STATUS);
if (tmp & SRBM_STATUS__VMC_BUSY_MASK)
srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset,
SRBM_SOFT_RESET, SOFT_RESET_VMC, 1);
if (tmp & (SRBM_STATUS__MCB_BUSY_MASK | SRBM_STATUS__MCB_NON_DISPLAY_BUSY_MASK |
SRBM_STATUS__MCC_BUSY_MASK | SRBM_STATUS__MCD_BUSY_MASK)) {
if (!(adev->flags & AMD_IS_APU))
srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset,
SRBM_SOFT_RESET, SOFT_RESET_MC, 1);
}
if (srbm_soft_reset) {
adev->gmc.srbm_soft_reset = srbm_soft_reset;
return true;
}
adev->gmc.srbm_soft_reset = 0;
return false;
}
static int gmc_v8_0_pre_soft_reset(struct amdgpu_ip_block *ip_block)
{
struct amdgpu_device *adev = ip_block->adev;
if (!adev->gmc.srbm_soft_reset)
return 0;
gmc_v8_0_mc_stop(adev);
if (gmc_v8_0_wait_for_idle(ip_block))
dev_warn(adev->dev, "Wait for GMC idle timed out !\n");
return 0;
}
static int gmc_v8_0_soft_reset(struct amdgpu_ip_block *ip_block)
{
struct amdgpu_device *adev = ip_block->adev;
u32 srbm_soft_reset;
if (!adev->gmc.srbm_soft_reset)
return 0;
srbm_soft_reset = adev->gmc.srbm_soft_reset;
if (srbm_soft_reset) {
u32 tmp;
tmp = RREG32(mmSRBM_SOFT_RESET);
tmp |= srbm_soft_reset;
dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp);
WREG32(mmSRBM_SOFT_RESET, tmp);
tmp = RREG32(mmSRBM_SOFT_RESET);
udelay(50);
tmp &= ~srbm_soft_reset;
WREG32(mmSRBM_SOFT_RESET, tmp);
tmp = RREG32(mmSRBM_SOFT_RESET);
/* Wait a little for things to settle down */
udelay(50);
}
return 0;
}
static int gmc_v8_0_post_soft_reset(struct amdgpu_ip_block *ip_block)
{
struct amdgpu_device *adev = ip_block->adev;
if (!adev->gmc.srbm_soft_reset)
return 0;
gmc_v8_0_mc_resume(adev);
return 0;
}
static int gmc_v8_0_vm_fault_interrupt_state(struct amdgpu_device *adev,
struct amdgpu_irq_src *src,
unsigned int type,
@@ -1715,10 +1594,6 @@ static const struct amd_ip_funcs gmc_v8_0_ip_funcs = {
.resume = gmc_v8_0_resume,
.is_idle = gmc_v8_0_is_idle,
.wait_for_idle = gmc_v8_0_wait_for_idle,
.check_soft_reset = gmc_v8_0_check_soft_reset,
.pre_soft_reset = gmc_v8_0_pre_soft_reset,
.soft_reset = gmc_v8_0_soft_reset,
.post_soft_reset = gmc_v8_0_post_soft_reset,
.set_clockgating_state = gmc_v8_0_set_clockgating_state,
.set_powergating_state = gmc_v8_0_set_powergating_state,
.get_clockgating_state = gmc_v8_0_get_clockgating_state,

View File

@@ -57,6 +57,7 @@
#include "umc_v6_0.h"
#include "umc_v6_7.h"
#include "umc_v12_0.h"
#include "ras_umc_v12_0.h"
#include "hdp_v4_0.h"
#include "mca_v3_0.h"
@@ -1382,7 +1383,7 @@ static void gmc_v9_0_set_umc_funcs(struct amdgpu_device *adev)
case IP_VERSION(12, 0, 0):
case IP_VERSION(12, 5, 0):
adev->umc.max_ras_err_cnt_per_query =
UMC_V12_0_TOTAL_CHANNEL_NUM(adev) * UMC_V12_0_BAD_PAGE_NUM_PER_CHANNEL;
UMC_V12_0_TOTAL_CHANNEL_NUM * UMC_V12_0_BAD_PAGE_NUM_PER_CHANNEL;
adev->umc.channel_inst_num = UMC_V12_0_CHANNEL_INSTANCE_NUM;
adev->umc.umc_inst_num = UMC_V12_0_UMC_INSTANCE_NUM;
adev->umc.node_inst_num /= UMC_V12_0_UMC_INSTANCE_NUM;
@@ -2025,11 +2026,19 @@ static int gmc_v9_0_sw_init(struct amdgpu_ip_block *ip_block)
* The first KFD VMID is 8 for GPUs with graphics, 3 for
* compute-only GPUs. On compute-only GPUs that leaves 2 VMIDs
* for video processing.
*
* If kernel queues are disabled, allow KFD to use all vmids.
*/
adev->vm_manager.first_kfd_vmid =
(amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 4, 1) ||
amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 4, 2) ||
amdgpu_is_multi_aid(adev)) ?
if (adev->gfx.disable_kq &&
adev->jpeg.disable_kq &&
adev->vcn.disable_kq &&
adev->sdma.no_user_submission)
adev->vm_manager.first_kfd_vmid = 1;
else
adev->vm_manager.first_kfd_vmid =
(amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 4, 1) ||
amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 4, 2) ||
amdgpu_is_multi_aid(adev)) ?
3 :
8;

View File

@@ -119,6 +119,19 @@ static int jpeg_v4_0_3_early_init(struct amdgpu_ip_block *ip_block)
{
struct amdgpu_device *adev = ip_block->adev;
switch (amdgpu_user_queue) {
case -1:
case 0:
default:
adev->jpeg.disable_kq = false;
adev->jpeg.disable_uq = true;
break;
case 2:
adev->jpeg.disable_kq = true;
adev->jpeg.disable_uq = true;
break;
}
adev->jpeg.num_jpeg_rings = AMDGPU_MAX_JPEG_RINGS_4_0_3;
jpeg_v4_0_3_set_dec_ring_funcs(adev);
@@ -175,6 +188,10 @@ static int jpeg_v4_0_3_sw_init(struct amdgpu_ip_block *ip_block)
for (j = 0; j < adev->jpeg.num_jpeg_rings; ++j) {
ring = &adev->jpeg.inst[i].ring_dec[j];
ring->use_doorbell = true;
if (adev->jpeg.disable_kq) {
ring->no_scheduler = true;
ring->no_user_submission = true;
}
ring->vm_hub = AMDGPU_MMHUB0(adev->jpeg.inst[i].aid_id);
if (!amdgpu_sriov_vf(adev)) {
ring->doorbell_index =
@@ -1425,72 +1442,6 @@ static const struct amdgpu_ras_block_hw_ops jpeg_v4_0_3_ras_hw_ops = {
.query_poison_status = jpeg_v4_0_3_query_ras_poison_status,
};
static int jpeg_v4_0_3_aca_bank_parser(struct aca_handle *handle, struct aca_bank *bank,
enum aca_smu_type type, void *data)
{
struct aca_bank_info info;
u64 misc0;
int ret;
ret = aca_bank_info_decode(bank, &info);
if (ret)
return ret;
misc0 = bank->regs[ACA_REG_IDX_MISC0];
switch (type) {
case ACA_SMU_TYPE_UE:
bank->aca_err_type = ACA_ERROR_TYPE_UE;
ret = aca_error_cache_log_bank_error(handle, &info, ACA_ERROR_TYPE_UE,
1ULL);
break;
case ACA_SMU_TYPE_CE:
bank->aca_err_type = ACA_ERROR_TYPE_CE;
ret = aca_error_cache_log_bank_error(handle, &info, bank->aca_err_type,
ACA_REG__MISC0__ERRCNT(misc0));
break;
default:
return -EINVAL;
}
return ret;
}
/* reference to smu driver if header file */
static int jpeg_v4_0_3_err_codes[] = {
16, 17, 18, 19, 20, 21, 22, 23, /* JPEG[0-7][S|D] */
24, 25, 26, 27, 28, 29, 30, 31
};
static bool jpeg_v4_0_3_aca_bank_is_valid(struct aca_handle *handle, struct aca_bank *bank,
enum aca_smu_type type, void *data)
{
u32 instlo;
instlo = ACA_REG__IPID__INSTANCEIDLO(bank->regs[ACA_REG_IDX_IPID]);
instlo &= GENMASK(31, 1);
if (instlo != mmSMNAID_AID0_MCA_SMU)
return false;
if (aca_bank_check_error_codes(handle->adev, bank,
jpeg_v4_0_3_err_codes,
ARRAY_SIZE(jpeg_v4_0_3_err_codes)))
return false;
return true;
}
static const struct aca_bank_ops jpeg_v4_0_3_aca_bank_ops = {
.aca_bank_parser = jpeg_v4_0_3_aca_bank_parser,
.aca_bank_is_valid = jpeg_v4_0_3_aca_bank_is_valid,
};
static const struct aca_info jpeg_v4_0_3_aca_info = {
.hwip = ACA_HWIP_TYPE_SMU,
.mask = ACA_ERROR_UE_MASK,
.bank_ops = &jpeg_v4_0_3_aca_bank_ops,
};
static int jpeg_v4_0_3_ras_late_init(struct amdgpu_device *adev, struct ras_common_if *ras_block)
{
int r;
@@ -1506,11 +1457,6 @@ static int jpeg_v4_0_3_ras_late_init(struct amdgpu_device *adev, struct ras_comm
goto late_fini;
}
r = amdgpu_ras_bind_aca(adev, AMDGPU_RAS_BLOCK__JPEG,
&jpeg_v4_0_3_aca_info, NULL);
if (r)
goto late_fini;
return 0;
late_fini:

View File

@@ -118,6 +118,19 @@ static int jpeg_v5_0_1_early_init(struct amdgpu_ip_block *ip_block)
if (!adev->jpeg.num_jpeg_inst || adev->jpeg.num_jpeg_inst > AMDGPU_MAX_JPEG_INSTANCES)
return -ENOENT;
switch (amdgpu_user_queue) {
case -1:
case 0:
default:
adev->jpeg.disable_kq = false;
adev->jpeg.disable_uq = true;
break;
case 2:
adev->jpeg.disable_kq = true;
adev->jpeg.disable_uq = true;
break;
}
adev->jpeg.num_jpeg_rings = AMDGPU_MAX_JPEG_RINGS;
jpeg_v5_0_1_set_dec_ring_funcs(adev);
jpeg_v5_0_1_set_irq_funcs(adev);
@@ -172,6 +185,10 @@ static int jpeg_v5_0_1_sw_init(struct amdgpu_ip_block *ip_block)
for (j = 0; j < adev->jpeg.num_jpeg_rings; ++j) {
ring = &adev->jpeg.inst[i].ring_dec[j];
ring->use_doorbell = true;
if (adev->jpeg.disable_kq) {
ring->no_scheduler = true;
ring->no_user_submission = true;
}
ring->vm_hub = AMDGPU_MMHUB0(adev->jpeg.inst[i].aid_id);
if (!amdgpu_sriov_vf(adev)) {
ring->doorbell_index =
@@ -871,10 +888,7 @@ static const struct amd_ip_funcs jpeg_v5_0_1_ip_funcs = {
.resume = jpeg_v5_0_1_resume,
.is_idle = jpeg_v5_0_1_is_idle,
.wait_for_idle = jpeg_v5_0_1_wait_for_idle,
.check_soft_reset = NULL,
.pre_soft_reset = NULL,
.soft_reset = NULL,
.post_soft_reset = NULL,
.set_clockgating_state = jpeg_v5_0_1_set_clockgating_state,
.set_powergating_state = jpeg_v5_0_1_set_powergating_state,
.dump_ip_state = amdgpu_jpeg_dump_ip_state,
@@ -1003,73 +1017,6 @@ static const struct amdgpu_ras_block_hw_ops jpeg_v5_0_1_ras_hw_ops = {
.query_poison_status = jpeg_v5_0_1_query_ras_poison_status,
};
static int jpeg_v5_0_1_aca_bank_parser(struct aca_handle *handle, struct aca_bank *bank,
enum aca_smu_type type, void *data)
{
struct aca_bank_info info;
u64 misc0;
int ret;
ret = aca_bank_info_decode(bank, &info);
if (ret)
return ret;
misc0 = bank->regs[ACA_REG_IDX_MISC0];
switch (type) {
case ACA_SMU_TYPE_UE:
bank->aca_err_type = ACA_ERROR_TYPE_UE;
ret = aca_error_cache_log_bank_error(handle, &info, ACA_ERROR_TYPE_UE,
1ULL);
break;
case ACA_SMU_TYPE_CE:
bank->aca_err_type = ACA_ERROR_TYPE_CE;
ret = aca_error_cache_log_bank_error(handle, &info, bank->aca_err_type,
ACA_REG__MISC0__ERRCNT(misc0));
break;
default:
return -EINVAL;
}
return ret;
}
/* reference to smu driver if header file */
static int jpeg_v5_0_1_err_codes[] = {
16, 17, 18, 19, 20, 21, 22, 23, /* JPEG[0-9][S|D] */
24, 25, 26, 27, 28, 29, 30, 31,
48, 49, 50, 51,
};
static bool jpeg_v5_0_1_aca_bank_is_valid(struct aca_handle *handle, struct aca_bank *bank,
enum aca_smu_type type, void *data)
{
u32 instlo;
instlo = ACA_REG__IPID__INSTANCEIDLO(bank->regs[ACA_REG_IDX_IPID]);
instlo &= GENMASK(31, 1);
if (instlo != mmSMNAID_AID0_MCA_SMU)
return false;
if (aca_bank_check_error_codes(handle->adev, bank,
jpeg_v5_0_1_err_codes,
ARRAY_SIZE(jpeg_v5_0_1_err_codes)))
return false;
return true;
}
static const struct aca_bank_ops jpeg_v5_0_1_aca_bank_ops = {
.aca_bank_parser = jpeg_v5_0_1_aca_bank_parser,
.aca_bank_is_valid = jpeg_v5_0_1_aca_bank_is_valid,
};
static const struct aca_info jpeg_v5_0_1_aca_info = {
.hwip = ACA_HWIP_TYPE_SMU,
.mask = ACA_ERROR_UE_MASK,
.bank_ops = &jpeg_v5_0_1_aca_bank_ops,
};
static int jpeg_v5_0_1_ras_late_init(struct amdgpu_device *adev, struct ras_common_if *ras_block)
{
int r;
@@ -1078,11 +1025,6 @@ static int jpeg_v5_0_1_ras_late_init(struct amdgpu_device *adev, struct ras_comm
if (r)
return r;
r = amdgpu_ras_bind_aca(adev, AMDGPU_RAS_BLOCK__JPEG,
&jpeg_v5_0_1_aca_info, NULL);
if (r)
goto late_fini;
if (amdgpu_ras_is_supported(adev, ras_block->block) &&
adev->jpeg.inst->ras_poison_irq.funcs) {
r = amdgpu_irq_get(adev, &adev->jpeg.inst->ras_poison_irq, 0);

View File

@@ -690,10 +690,7 @@ static const struct amd_ip_funcs jpeg_v5_0_2_ip_funcs = {
.resume = jpeg_v5_0_2_resume,
.is_idle = jpeg_v5_0_2_is_idle,
.wait_for_idle = jpeg_v5_0_2_wait_for_idle,
.check_soft_reset = NULL,
.pre_soft_reset = NULL,
.soft_reset = NULL,
.post_soft_reset = NULL,
.set_clockgating_state = jpeg_v5_0_2_set_clockgating_state,
.set_powergating_state = jpeg_v5_0_2_set_powergating_state,
.dump_ip_state = amdgpu_jpeg_dump_ip_state,

View File

@@ -133,8 +133,8 @@ static int mes_userq_map(struct amdgpu_usermode_queue *queue)
queue_input.gang_quantum = 10000;
queue_input.paging = false;
queue_input.process_context_addr = ctx->gpu_addr;
queue_input.gang_context_addr = ctx->gpu_addr + AMDGPU_USERQ_PROC_CTX_SZ;
queue_input.process_context_addr = uq_mgr->proc_ctx_obj.gpu_addr;
queue_input.gang_context_addr = ctx->gpu_addr;
queue_input.inprocess_gang_priority = AMDGPU_MES_PRIORITY_LEVEL_NORMAL;
queue_input.gang_global_priority_level = convert_to_mes_priority(queue->priority);
@@ -169,7 +169,8 @@ static int mes_userq_unmap(struct amdgpu_usermode_queue *queue)
memset(&queue_input, 0x0, sizeof(struct mes_remove_queue_input));
queue_input.doorbell_offset = queue->doorbell_index;
queue_input.gang_context_addr = ctx->gpu_addr + AMDGPU_USERQ_PROC_CTX_SZ;
queue_input.gang_context_addr = ctx->gpu_addr;
queue_input.queue_type = queue->queue_type;
amdgpu_mes_lock(&adev->mes);
r = adev->mes.funcs->remove_hw_queue(&adev->mes, &queue_input);
@@ -179,6 +180,63 @@ static int mes_userq_unmap(struct amdgpu_usermode_queue *queue)
return r;
}
int mes_userq_reset(struct amdgpu_usermode_queue *queue)
{
struct amdgpu_userq_mgr *uq_mgr = queue->userq_mgr;
struct amdgpu_device *adev = uq_mgr->adev;
struct mes_reset_queue_input queue_input;
int r;
/* XXX: add a FW version check for SDMA per queue reset */
memset(&queue_input, 0x0, sizeof(struct mes_reset_queue_input));
queue_input.doorbell_offset = queue->doorbell_index;
queue_input.queue_type = queue->queue_type;
amdgpu_mes_lock(&adev->mes);
r = adev->mes.funcs->reset_hw_queue(&adev->mes, &queue_input);
amdgpu_mes_unlock(&adev->mes);
if (r)
return r;
return mes_userq_unmap(queue);
}
int mes_userq_reset_queue(struct amdgpu_device *adev,
struct amdgpu_usermode_queue *guilty_uq,
int queue_type,
unsigned int pipe,
unsigned int queue,
unsigned int db)
{
struct amdgpu_usermode_queue *uq;
bool use_mmio = adev->gfx.mec.use_mmio_for_reset;
unsigned long uq_id;
int r;
xa_for_each(&adev->userq_doorbell_xa, uq_id, uq) {
if (uq->queue_type == queue_type) {
if (uq == guilty_uq)
continue;
if (uq->doorbell_index == db) {
uq->state = AMDGPU_USERQ_STATE_HUNG;
if (use_mmio)
r = amdgpu_mes_reset_queue_mmio(adev, queue_type, 0, 1, pipe, queue, 0);
else
r = amdgpu_mes_reset_user_queue(adev, queue_type, db, 0);
if (r)
return r;
r = mes_userq_unmap(uq);
if (r)
return r;
atomic_inc(&adev->gpu_reset_counter);
amdgpu_userq_fence_driver_force_completion(uq);
drm_dev_wedged_event(adev_to_drm(adev), DRM_WEDGE_RECOVERY_NONE, NULL);
break;
}
}
}
return 0;
}
static int mes_userq_create_ctx_space(struct amdgpu_userq_mgr *uq_mgr,
struct amdgpu_usermode_queue *queue,
struct drm_amdgpu_userq_in *mqd_user)
@@ -186,12 +244,8 @@ static int mes_userq_create_ctx_space(struct amdgpu_userq_mgr *uq_mgr,
struct amdgpu_userq_obj *ctx = &queue->fw_obj;
int r, size;
/*
* The FW expects at least one page space allocated for
* process ctx and gang ctx each. Create an object
* for the same.
*/
size = AMDGPU_USERQ_PROC_CTX_SZ + AMDGPU_USERQ_GANG_CTX_SZ;
/* The FW expects at least one page space allocated for gang ctx. */
size = AMDGPU_USERQ_GANG_CTX_SZ;
r = amdgpu_bo_create_kernel(uq_mgr->adev, size, 0,
AMDGPU_GEM_DOMAIN_GTT,
&ctx->obj, &ctx->gpu_addr,
@@ -205,54 +259,26 @@ static int mes_userq_create_ctx_space(struct amdgpu_userq_mgr *uq_mgr,
return 0;
}
static int mes_userq_detect_and_reset(struct amdgpu_device *adev,
int queue_type)
static int mes_userq_create_proc_ctx_space(struct amdgpu_userq_mgr *uq_mgr)
{
int db_array_size = amdgpu_mes_get_hung_queue_db_array_size(adev);
struct mes_detect_and_reset_queue_input input;
struct amdgpu_usermode_queue *queue;
unsigned int hung_db_num = 0;
unsigned long queue_id;
u32 db_array[8];
bool found_hung_queue = false;
int r, i;
int r = 0;
if (db_array_size > 8) {
dev_err(adev->dev, "DB array size (%d vs 8) too small\n",
db_array_size);
return -EINVAL;
mutex_lock(&uq_mgr->proc_ctx_lock);
/* This check is a necessary because amdgpu_bo_create_kernel()
* calls helpers like amdgpu_bo_pin() and memset() unconditionally
*/
if (!uq_mgr->proc_ctx_obj.obj) {
r = amdgpu_bo_create_kernel(uq_mgr->adev, AMDGPU_USERQ_PROC_CTX_SZ,
0, AMDGPU_GEM_DOMAIN_GTT,
&uq_mgr->proc_ctx_obj.obj,
&uq_mgr->proc_ctx_obj.gpu_addr,
&uq_mgr->proc_ctx_obj.cpu_ptr);
if (!r)
memset(uq_mgr->proc_ctx_obj.cpu_ptr, 0, AMDGPU_USERQ_PROC_CTX_SZ);
}
memset(&input, 0x0, sizeof(struct mes_detect_and_reset_queue_input));
input.queue_type = queue_type;
amdgpu_mes_lock(&adev->mes);
r = amdgpu_mes_detect_and_reset_hung_queues(adev, queue_type, false,
&hung_db_num, db_array, 0);
amdgpu_mes_unlock(&adev->mes);
if (r) {
dev_err(adev->dev, "Failed to detect and reset queues, err (%d)\n", r);
} else if (hung_db_num) {
xa_for_each(&adev->userq_doorbell_xa, queue_id, queue) {
if (queue->queue_type == queue_type) {
for (i = 0; i < hung_db_num; i++) {
if (queue->doorbell_index == db_array[i]) {
queue->state = AMDGPU_USERQ_STATE_HUNG;
found_hung_queue = true;
atomic_inc(&adev->gpu_reset_counter);
amdgpu_userq_fence_driver_force_completion(queue);
drm_dev_wedged_event(adev_to_drm(adev), DRM_WEDGE_RECOVERY_NONE, NULL);
}
}
}
}
}
if (found_hung_queue) {
/* Resume scheduling after hang recovery */
r = amdgpu_mes_resume(adev, input.xcc_id);
}
mutex_unlock(&uq_mgr->proc_ctx_lock);
return r;
}
@@ -429,7 +455,14 @@ static int mes_userq_mqd_create(struct amdgpu_usermode_queue *queue,
goto free_mqd;
}
/* Create BO for FW operations */
/* Create per-process MES process context BO */
r = mes_userq_create_proc_ctx_space(uq_mgr);
if (r) {
DRM_ERROR("Failed to allocate MES process context space bo, error: %d\n", r);
goto free_mqd;
}
/* Create BO of a gang for FW operations */
r = mes_userq_create_ctx_space(uq_mgr, queue, mqd_user);
if (r) {
DRM_ERROR("Failed to allocate BO for userqueue (%d)", r);
@@ -497,7 +530,7 @@ static int mes_userq_preempt(struct amdgpu_usermode_queue *queue)
*fence_ptr = 0;
memset(&queue_input, 0x0, sizeof(struct mes_suspend_gang_input));
queue_input.gang_context_addr = ctx->gpu_addr + AMDGPU_USERQ_PROC_CTX_SZ;
queue_input.gang_context_addr = ctx->gpu_addr;
queue_input.suspend_fence_addr = fence_gpu_addr;
queue_input.suspend_fence_value = 1;
amdgpu_mes_lock(&adev->mes);
@@ -534,7 +567,7 @@ static int mes_userq_restore(struct amdgpu_usermode_queue *queue)
return 0;
memset(&queue_input, 0x0, sizeof(struct mes_resume_gang_input));
queue_input.gang_context_addr = ctx->gpu_addr + AMDGPU_USERQ_PROC_CTX_SZ;
queue_input.gang_context_addr = ctx->gpu_addr;
amdgpu_mes_lock(&adev->mes);
r = adev->mes.funcs->resume_gang(&adev->mes, &queue_input);
@@ -549,7 +582,7 @@ const struct amdgpu_userq_funcs userq_mes_funcs = {
.mqd_destroy = mes_userq_mqd_destroy,
.unmap = mes_userq_unmap,
.map = mes_userq_map,
.detect_and_reset = mes_userq_detect_and_reset,
.preempt = mes_userq_preempt,
.restore = mes_userq_restore,
.reset = mes_userq_reset,
};

View File

@@ -27,4 +27,13 @@
#include "amdgpu_userq.h"
extern const struct amdgpu_userq_funcs userq_mes_funcs;
int mes_userq_reset(struct amdgpu_usermode_queue *queue);
int mes_userq_reset_queue(struct amdgpu_device *adev,
struct amdgpu_usermode_queue *guilty_uq,
int queue_type,
unsigned int pipe,
unsigned int queue,
unsigned int db);
#endif

View File

@@ -387,6 +387,8 @@ static int mes_v11_0_remove_hw_queue(struct amdgpu_mes *mes,
mes_remove_queue_pkt.doorbell_offset = input->doorbell_offset;
mes_remove_queue_pkt.gang_context_addr = input->gang_context_addr;
mes_remove_queue_pkt.queue_type =
convert_to_mes_queue_type(input->queue_type);
if (mes_rev >= 0x60)
mes_remove_queue_pkt.remove_queue_after_reset = input->remove_queue_after_reset;
@@ -396,6 +398,230 @@ static int mes_v11_0_remove_hw_queue(struct amdgpu_mes *mes,
offsetof(union MESAPI__REMOVE_QUEUE, api_status));
}
static bool mes_v11_0_pipe_reset_support(struct amdgpu_device *adev)
{
/* Disable the pipe reset until the CPFW fully support it.*/
dev_warn_once(adev->dev, "The CPFW hasn't support pipe reset yet.\n");
return false;
}
static int mes_v11_0_reset_gfx_pipe_mmio(struct amdgpu_device *adev,
u32 me, u32 pipe, u32 queue)
{
uint32_t reset_pipe = 0, clean_pipe = 0;
int r;
if (!mes_v11_0_pipe_reset_support(adev))
return -EOPNOTSUPP;
amdgpu_gfx_rlc_enter_safe_mode(adev, 0);
mutex_lock(&adev->srbm_mutex);
soc21_grbm_select(adev, me, pipe, queue, 0);
switch (pipe) {
case 0:
reset_pipe = REG_SET_FIELD(reset_pipe, CP_ME_CNTL,
PFP_PIPE0_RESET, 1);
reset_pipe = REG_SET_FIELD(reset_pipe, CP_ME_CNTL,
ME_PIPE0_RESET, 1);
clean_pipe = REG_SET_FIELD(clean_pipe, CP_ME_CNTL,
PFP_PIPE0_RESET, 0);
clean_pipe = REG_SET_FIELD(clean_pipe, CP_ME_CNTL,
ME_PIPE0_RESET, 0);
break;
case 1:
reset_pipe = REG_SET_FIELD(reset_pipe, CP_ME_CNTL,
PFP_PIPE1_RESET, 1);
reset_pipe = REG_SET_FIELD(reset_pipe, CP_ME_CNTL,
ME_PIPE1_RESET, 1);
clean_pipe = REG_SET_FIELD(clean_pipe, CP_ME_CNTL,
PFP_PIPE1_RESET, 0);
clean_pipe = REG_SET_FIELD(clean_pipe, CP_ME_CNTL,
ME_PIPE1_RESET, 0);
break;
default:
break;
}
WREG32_SOC15(GC, 0, regCP_ME_CNTL, reset_pipe);
WREG32_SOC15(GC, 0, regCP_ME_CNTL, clean_pipe);
r = (RREG32(SOC15_REG_OFFSET(GC, 0, regCP_GFX_RS64_INSTR_PNTR1)) << 2) -
RS64_FW_UC_START_ADDR_LO;
soc21_grbm_select(adev, 0, 0, 0, 0);
mutex_unlock(&adev->srbm_mutex);
amdgpu_gfx_rlc_exit_safe_mode(adev, 0);
dev_info(adev->dev, "The gfx pipe reset to the ME firmware start PC: %s\n",
r == 0 ? "successfully" : "failed");
/* FIXME: Sometimes driver can't cache the ME firmware start PC correctly,
* so the pipe reset status relies on the later gfx ring test result.
*/
return 0;
}
/*
* With MEC pipe reset asserted, clear CP_HQD_ACTIVE / CP_HQD_DEQUEUE_REQUEST for
* every queue on (me, pipe). HQDs must be torn down while pipe reset stays
* asserted; only then clear the pipe reset bit.
* Caller must hold adev->srbm_mutex.
*/
static void mes_v11_0_clear_hqds_on_mec_pipe(struct amdgpu_device *adev, u32 me,
u32 pipe)
{
unsigned int q;
for (q = 0; q < adev->gfx.mec.num_queue_per_pipe; q++) {
soc21_grbm_select(adev, me, pipe, q, 0);
/* Start from a clean HQD dequeue state before forcing HQD inactive. */
WREG32_SOC15(GC, 0, regCP_HQD_ACTIVE, 0);
WREG32_SOC15(GC, 0, regCP_HQD_DEQUEUE_REQUEST, 0);
}
}
static int mes_v11_0_reset_compute_pipe_mmio(struct amdgpu_device *adev,
u32 me, u32 pipe, u32 queue)
{
uint32_t reset_val, clean_val;
int r;
amdgpu_gfx_rlc_enter_safe_mode(adev, 0);
mutex_lock(&adev->srbm_mutex);
soc21_grbm_select(adev, me, pipe, queue, 0);
if (adev->gfx.rs64_enable) {
reset_val = RREG32_SOC15(GC, 0, regCP_MEC_RS64_CNTL);
clean_val = reset_val;
switch (pipe) {
case 0:
reset_val = REG_SET_FIELD(reset_val, CP_MEC_RS64_CNTL,
MEC_PIPE0_RESET, 1);
clean_val = REG_SET_FIELD(clean_val, CP_MEC_RS64_CNTL,
MEC_PIPE0_RESET, 0);
break;
case 1:
reset_val = REG_SET_FIELD(reset_val, CP_MEC_RS64_CNTL,
MEC_PIPE1_RESET, 1);
clean_val = REG_SET_FIELD(clean_val, CP_MEC_RS64_CNTL,
MEC_PIPE1_RESET, 0);
break;
case 2:
reset_val = REG_SET_FIELD(reset_val, CP_MEC_RS64_CNTL,
MEC_PIPE2_RESET, 1);
clean_val = REG_SET_FIELD(clean_val, CP_MEC_RS64_CNTL,
MEC_PIPE2_RESET, 0);
break;
case 3:
reset_val = REG_SET_FIELD(reset_val, CP_MEC_RS64_CNTL,
MEC_PIPE3_RESET, 1);
clean_val = REG_SET_FIELD(clean_val, CP_MEC_RS64_CNTL,
MEC_PIPE3_RESET, 0);
break;
default:
break;
}
WREG32_SOC15(GC, 0, regCP_MEC_RS64_CNTL, reset_val);
mes_v11_0_clear_hqds_on_mec_pipe(adev, me, pipe);
WREG32_SOC15(GC, 0, regCP_MEC_RS64_CNTL, clean_val);
r = (RREG32_SOC15(GC, 0, regCP_MEC_RS64_INSTR_PNTR) << 2) -
RS64_FW_UC_START_ADDR_LO;
} else {
reset_val = RREG32_SOC15(GC, 0, regCP_MEC_CNTL);
clean_val = reset_val;
if (me == 1) {
switch (pipe) {
case 0:
reset_val = REG_SET_FIELD(reset_val, CP_MEC_CNTL,
MEC_ME1_PIPE0_RESET, 1);
clean_val = REG_SET_FIELD(clean_val, CP_MEC_CNTL,
MEC_ME1_PIPE0_RESET, 0);
break;
case 1:
reset_val = REG_SET_FIELD(reset_val, CP_MEC_CNTL,
MEC_ME1_PIPE1_RESET, 1);
clean_val = REG_SET_FIELD(clean_val, CP_MEC_CNTL,
MEC_ME1_PIPE1_RESET, 0);
break;
case 2:
reset_val = REG_SET_FIELD(reset_val, CP_MEC_CNTL,
MEC_ME1_PIPE2_RESET, 1);
clean_val = REG_SET_FIELD(clean_val, CP_MEC_CNTL,
MEC_ME1_PIPE2_RESET, 0);
break;
case 3:
reset_val = REG_SET_FIELD(reset_val, CP_MEC_CNTL,
MEC_ME1_PIPE3_RESET, 1);
clean_val = REG_SET_FIELD(clean_val, CP_MEC_CNTL,
MEC_ME1_PIPE3_RESET, 0);
break;
default:
break;
}
/* mec1 fw pc: CP_MEC1_INSTR_PNTR */
} else {
switch (pipe) {
case 0:
reset_val = REG_SET_FIELD(reset_val, CP_MEC_CNTL,
MEC_ME2_PIPE0_RESET, 1);
clean_val = REG_SET_FIELD(clean_val, CP_MEC_CNTL,
MEC_ME2_PIPE0_RESET, 0);
break;
case 1:
reset_val = REG_SET_FIELD(reset_val, CP_MEC_CNTL,
MEC_ME2_PIPE1_RESET, 1);
clean_val = REG_SET_FIELD(clean_val, CP_MEC_CNTL,
MEC_ME2_PIPE1_RESET, 0);
break;
case 2:
reset_val = REG_SET_FIELD(reset_val, CP_MEC_CNTL,
MEC_ME2_PIPE2_RESET, 1);
clean_val = REG_SET_FIELD(clean_val, CP_MEC_CNTL,
MEC_ME2_PIPE2_RESET, 0);
break;
case 3:
reset_val = REG_SET_FIELD(reset_val, CP_MEC_CNTL,
MEC_ME2_PIPE3_RESET, 1);
clean_val = REG_SET_FIELD(clean_val, CP_MEC_CNTL,
MEC_ME2_PIPE3_RESET, 0);
break;
default:
break;
}
/* mec2 fw pc: CP:CP_MEC2_INSTR_PNTR */
}
WREG32_SOC15(GC, 0, regCP_MEC_CNTL, reset_val);
mes_v11_0_clear_hqds_on_mec_pipe(adev, me, pipe);
WREG32_SOC15(GC, 0, regCP_MEC_CNTL, clean_val);
r = RREG32(SOC15_REG_OFFSET(GC, 0, regCP_MEC1_INSTR_PNTR));
}
soc21_grbm_select(adev, 0, 0, 0, 0);
mutex_unlock(&adev->srbm_mutex);
amdgpu_gfx_rlc_exit_safe_mode(adev, 0);
dev_dbg(adev->dev, "MEC pipe me%u pipe%u queue%u resets to MEC FW start PC: %s\n",
me, pipe, queue, r == 0 ? "successfully" : "failed");
/*FIXME:Sometimes driver can't cache the MEC firmware start PC correctly, so the pipe
* reset status relies on the compute ring test result.
*/
return 0;
}
static int mes_v11_0_reset_pipe_mmio(struct amdgpu_mes *mes, uint32_t queue_type,
uint32_t me_id, uint32_t pipe_id,
uint32_t queue_id, uint32_t vmid)
{
struct amdgpu_device *adev = mes->adev;
if (queue_type == AMDGPU_RING_TYPE_GFX)
return mes_v11_0_reset_gfx_pipe_mmio(adev, me_id, pipe_id, queue_id);
else if (queue_type == AMDGPU_RING_TYPE_COMPUTE)
return mes_v11_0_reset_compute_pipe_mmio(adev, me_id, pipe_id, queue_id);
else
return -EOPNOTSUPP;
}
static int mes_v11_0_reset_queue_mmio(struct amdgpu_mes *mes, uint32_t queue_type,
uint32_t me_id, uint32_t pipe_id,
uint32_t queue_id, uint32_t vmid)
@@ -770,10 +996,16 @@ static int mes_v11_0_reset_hw_queue(struct amdgpu_mes *mes,
{
union MESAPI__RESET mes_reset_queue_pkt;
if (input->use_mmio)
return mes_v11_0_reset_queue_mmio(mes, input->queue_type,
input->me_id, input->pipe_id,
input->queue_id, input->vmid);
if (input->use_mmio) {
int r = mes_v11_0_reset_queue_mmio(mes, input->queue_type,
input->me_id, input->pipe_id,
input->queue_id, input->vmid);
if (r)
return mes_v11_0_reset_pipe_mmio(mes, input->queue_type,
input->me_id, input->pipe_id,
input->queue_id, input->vmid);
return 0;
}
memset(&mes_reset_queue_pkt, 0, sizeof(mes_reset_queue_pkt));

View File

@@ -26,7 +26,7 @@
#include "amdgpu.h"
#include "gfx_v12_0.h"
#include "soc15_common.h"
#include "soc21.h"
#include "soc24.h"
#include "gc/gc_12_0_0_offset.h"
#include "gc/gc_12_0_0_sh_mask.h"
#include "gc/gc_11_0_0_default.h"
@@ -371,6 +371,8 @@ static int mes_v12_0_remove_hw_queue(struct amdgpu_mes *mes,
mes_remove_queue_pkt.doorbell_offset = input->doorbell_offset;
mes_remove_queue_pkt.gang_context_addr = input->gang_context_addr;
mes_remove_queue_pkt.queue_type =
convert_to_mes_queue_type(input->queue_type);
if (mes_rev >= 0x5a)
mes_remove_queue_pkt.remove_queue_after_reset = input->remove_queue_after_reset;
@@ -413,6 +415,171 @@ int gfx_v12_0_request_gfx_index_mutex(struct amdgpu_device *adev,
return 0;
}
static bool mes_v12_0_pipe_reset_support(struct amdgpu_device *adev)
{
/* Disable the pipe reset until the CPFW fully support it.*/
dev_warn_once(adev->dev, "The CPFW hasn't support pipe reset yet.\n");
return false;
}
static int mes_v12_0_reset_gfx_pipe_mmio(struct amdgpu_device *adev,
u32 me, u32 pipe, u32 queue)
{
uint32_t reset_pipe = 0, clean_pipe = 0;
int r;
if (!mes_v12_0_pipe_reset_support(adev))
return -EOPNOTSUPP;
amdgpu_gfx_rlc_enter_safe_mode(adev, 0);
mutex_lock(&adev->srbm_mutex);
soc24_grbm_select(adev, me, pipe, queue, 0);
switch (pipe) {
case 0:
reset_pipe = REG_SET_FIELD(reset_pipe, CP_ME_CNTL,
PFP_PIPE0_RESET, 1);
reset_pipe = REG_SET_FIELD(reset_pipe, CP_ME_CNTL,
ME_PIPE0_RESET, 1);
clean_pipe = REG_SET_FIELD(clean_pipe, CP_ME_CNTL,
PFP_PIPE0_RESET, 0);
clean_pipe = REG_SET_FIELD(clean_pipe, CP_ME_CNTL,
ME_PIPE0_RESET, 0);
break;
case 1:
reset_pipe = REG_SET_FIELD(reset_pipe, CP_ME_CNTL,
PFP_PIPE1_RESET, 1);
reset_pipe = REG_SET_FIELD(reset_pipe, CP_ME_CNTL,
ME_PIPE1_RESET, 1);
clean_pipe = REG_SET_FIELD(clean_pipe, CP_ME_CNTL,
PFP_PIPE1_RESET, 0);
clean_pipe = REG_SET_FIELD(clean_pipe, CP_ME_CNTL,
ME_PIPE1_RESET, 0);
break;
default:
break;
}
WREG32_SOC15(GC, 0, regCP_ME_CNTL, reset_pipe);
WREG32_SOC15(GC, 0, regCP_ME_CNTL, clean_pipe);
r = (RREG32(SOC15_REG_OFFSET(GC, 0, regCP_GFX_RS64_INSTR_PNTR1)) << 2) -
RS64_FW_UC_START_ADDR_LO;
soc24_grbm_select(adev, 0, 0, 0, 0);
mutex_unlock(&adev->srbm_mutex);
amdgpu_gfx_rlc_exit_safe_mode(adev, 0);
dev_info(adev->dev, "The gfx pipe reset: %s\n",
r == 0 ? "successfully" : "failed");
/* Sometimes the ME start pc counter can't cache correctly, so the
* PC check only as a reference and pipe reset result rely on the
* later ring test.
*/
return 0;
}
/*
* With MEC pipe reset asserted, clear CP_HQD_ACTIVE / CP_HQD_DEQUEUE_REQUEST for
* every queue on (me, pipe). HQDs must be torn down while pipe reset stays
* asserted; only then clear the pipe reset bit.
* Caller must hold adev->srbm_mutex.
*/
static void mes_v12_0_clear_hqds_on_mec_pipe(struct amdgpu_device *adev, u32 me,
u32 pipe)
{
unsigned int q;
for (q = 0; q < adev->gfx.mec.num_queue_per_pipe; q++) {
soc24_grbm_select(adev, me, pipe, q, 0);
/* Start from a clean HQD dequeue state before forcing HQD inactive. */
WREG32_SOC15(GC, 0, regCP_HQD_ACTIVE, 0);
WREG32_SOC15(GC, 0, regCP_HQD_DEQUEUE_REQUEST, 0);
}
}
static int mes_v12_0_reset_compute_pipe_mmio(struct amdgpu_device *adev,
u32 me, u32 pipe, u32 queue)
{
uint32_t reset_val, clean_val;
int r = 0;
amdgpu_gfx_rlc_enter_safe_mode(adev, 0);
mutex_lock(&adev->srbm_mutex);
soc24_grbm_select(adev, me, pipe, queue, 0);
if (adev->gfx.rs64_enable) {
reset_val = RREG32_SOC15(GC, 0, regCP_MEC_RS64_CNTL);
clean_val = reset_val;
switch (pipe) {
case 0:
reset_val = REG_SET_FIELD(reset_val, CP_MEC_RS64_CNTL,
MEC_PIPE0_RESET, 1);
clean_val = REG_SET_FIELD(clean_val, CP_MEC_RS64_CNTL,
MEC_PIPE0_RESET, 0);
break;
case 1:
reset_val = REG_SET_FIELD(reset_val, CP_MEC_RS64_CNTL,
MEC_PIPE1_RESET, 1);
clean_val = REG_SET_FIELD(clean_val, CP_MEC_RS64_CNTL,
MEC_PIPE1_RESET, 0);
break;
case 2:
reset_val = REG_SET_FIELD(reset_val, CP_MEC_RS64_CNTL,
MEC_PIPE2_RESET, 1);
clean_val = REG_SET_FIELD(clean_val, CP_MEC_RS64_CNTL,
MEC_PIPE2_RESET, 0);
break;
case 3:
reset_val = REG_SET_FIELD(reset_val, CP_MEC_RS64_CNTL,
MEC_PIPE3_RESET, 1);
clean_val = REG_SET_FIELD(clean_val, CP_MEC_RS64_CNTL,
MEC_PIPE3_RESET, 0);
break;
default:
break;
}
WREG32_SOC15(GC, 0, regCP_MEC_RS64_CNTL, reset_val);
mes_v12_0_clear_hqds_on_mec_pipe(adev, me, pipe);
soc24_grbm_select(adev, me, pipe, queue, 0);
WREG32_SOC15(GC, 0, regCP_MEC_RS64_CNTL, clean_val);
r = (RREG32_SOC15(GC, 0, regCP_MEC_RS64_INSTR_PNTR) << 2) -
RS64_FW_UC_START_ADDR_LO;
} else {
reset_val = RREG32_SOC15(GC, 0, regCP_MEC_CNTL);
clean_val = reset_val;
switch (pipe) {
case 0:
reset_val = REG_SET_FIELD(reset_val, CP_MEC_CNTL,
MEC_ME1_PIPE0_RESET, 1);
clean_val = REG_SET_FIELD(clean_val, CP_MEC_CNTL,
MEC_ME1_PIPE0_RESET, 0);
break;
case 1:
reset_val = REG_SET_FIELD(reset_val, CP_MEC_CNTL,
MEC_ME1_PIPE1_RESET, 1);
clean_val = REG_SET_FIELD(clean_val, CP_MEC_CNTL,
MEC_ME1_PIPE1_RESET, 0);
break;
default:
break;
}
WREG32_SOC15(GC, 0, regCP_MEC_CNTL, reset_val);
mes_v12_0_clear_hqds_on_mec_pipe(adev, me, pipe);
soc24_grbm_select(adev, me, pipe, queue, 0);
WREG32_SOC15(GC, 0, regCP_MEC_CNTL, clean_val);
}
soc24_grbm_select(adev, 0, 0, 0, 0);
mutex_unlock(&adev->srbm_mutex);
amdgpu_gfx_rlc_exit_safe_mode(adev, 0);
dev_dbg(adev->dev, "MEC pipe me%u pipe%u queue%u resets to MEC FW start PC: %s\n",
me, pipe, queue, r == 0 ? "successfully" : "failed");
return 0;
}
static int mes_v12_0_reset_queue_mmio(struct amdgpu_mes *mes, uint32_t queue_type,
uint32_t me_id, uint32_t pipe_id,
uint32_t queue_id, uint32_t vmid)
@@ -442,7 +609,7 @@ static int mes_v12_0_reset_queue_mmio(struct amdgpu_mes *mes, uint32_t queue_typ
mutex_unlock(&adev->gfx.reset_sem_mutex);
mutex_lock(&adev->srbm_mutex);
soc21_grbm_select(adev, me_id, pipe_id, queue_id, 0);
soc24_grbm_select(adev, me_id, pipe_id, queue_id, 0);
/* wait till dequeue take effects */
for (i = 0; i < adev->usec_timeout; i++) {
if (!(RREG32_SOC15(GC, 0, regCP_GFX_HQD_ACTIVE) & 1))
@@ -454,13 +621,13 @@ static int mes_v12_0_reset_queue_mmio(struct amdgpu_mes *mes, uint32_t queue_typ
r = -ETIMEDOUT;
}
soc21_grbm_select(adev, 0, 0, 0, 0);
soc24_grbm_select(adev, 0, 0, 0, 0);
mutex_unlock(&adev->srbm_mutex);
} else if (queue_type == AMDGPU_RING_TYPE_COMPUTE) {
dev_info(adev->dev, "reset compute queue (%d:%d:%d)\n",
me_id, pipe_id, queue_id);
mutex_lock(&adev->srbm_mutex);
soc21_grbm_select(adev, me_id, pipe_id, queue_id, 0);
soc24_grbm_select(adev, me_id, pipe_id, queue_id, 0);
WREG32_SOC15(GC, 0, regCP_HQD_DEQUEUE_REQUEST, 0x2);
WREG32_SOC15(GC, 0, regSPI_COMPUTE_QUEUE_RESET, 0x1);
@@ -474,7 +641,7 @@ static int mes_v12_0_reset_queue_mmio(struct amdgpu_mes *mes, uint32_t queue_typ
dev_err(adev->dev, "failed to wait on hqd deactivate\n");
r = -ETIMEDOUT;
}
soc21_grbm_select(adev, 0, 0, 0, 0);
soc24_grbm_select(adev, 0, 0, 0, 0);
mutex_unlock(&adev->srbm_mutex);
} else if (queue_type == AMDGPU_RING_TYPE_SDMA) {
dev_info(adev->dev, "reset sdma queue (%d:%d:%d)\n",
@@ -507,6 +674,20 @@ static int mes_v12_0_reset_queue_mmio(struct amdgpu_mes *mes, uint32_t queue_typ
return r;
}
static int mes_v12_0_reset_pipe_mmio(struct amdgpu_mes *mes, uint32_t queue_type,
uint32_t me_id, uint32_t pipe_id,
uint32_t queue_id, uint32_t vmid)
{
struct amdgpu_device *adev = mes->adev;
if (queue_type == AMDGPU_RING_TYPE_GFX)
return mes_v12_0_reset_gfx_pipe_mmio(adev, me_id, pipe_id, queue_id);
else if (queue_type == AMDGPU_RING_TYPE_COMPUTE)
return mes_v12_0_reset_compute_pipe_mmio(adev, me_id, pipe_id, queue_id);
else
return -EOPNOTSUPP;
}
static int mes_v12_0_map_legacy_queue(struct amdgpu_mes *mes,
struct mes_map_legacy_queue_input *input)
{
@@ -528,10 +709,15 @@ static int mes_v12_0_map_legacy_queue(struct amdgpu_mes *mes,
convert_to_mes_queue_type(input->queue_type);
mes_add_queue_pkt.map_legacy_kq = 1;
if (mes->adev->enable_uni_mes)
pipe = AMDGPU_MES_KIQ_PIPE;
else
if (mes->adev->enable_uni_mes) {
/* Keep scheduler queue on KIQ pipe; map all other kernel queues on sched pipe. */
if (input->queue_type == AMDGPU_RING_TYPE_MES)
pipe = AMDGPU_MES_KIQ_PIPE;
else
pipe = AMDGPU_MES_SCHED_PIPE;
} else {
pipe = AMDGPU_MES_SCHED_PIPE;
}
return mes_v12_0_submit_pkt_and_poll_completion(mes, pipe,
&mes_add_queue_pkt, sizeof(mes_add_queue_pkt),
@@ -565,12 +751,28 @@ static int mes_v12_0_unmap_legacy_queue(struct amdgpu_mes *mes,
mes_remove_queue_pkt.unmap_legacy_queue = 1;
mes_remove_queue_pkt.queue_type =
convert_to_mes_queue_type(input->queue_type);
/*
* A reset-time unmap: the queue was already reset via MMIO while
* gangs are suspended and it is on the MES hung/fail list. Tell
* MES to just drop its internal state for it. Without this flag
* MES asks CP to unmap the already-reset (still wedged) queue
* again, which times out and forces a GPU reset.
*/
if (input->action == RESET_QUEUES &&
(mes->sched_version & AMDGPU_MES_VERSION_MASK) >= 0x5a)
mes_remove_queue_pkt.remove_queue_after_reset = 1;
}
if (mes->adev->enable_uni_mes)
pipe = AMDGPU_MES_KIQ_PIPE;
else
if (mes->adev->enable_uni_mes) {
/* Keep scheduler queue on KIQ pipe; unmap all other kernel queues on sched pipe. */
if (input->queue_type == AMDGPU_RING_TYPE_MES)
pipe = AMDGPU_MES_KIQ_PIPE;
else
pipe = AMDGPU_MES_SCHED_PIPE;
} else {
pipe = AMDGPU_MES_SCHED_PIPE;
}
return mes_v12_0_submit_pkt_and_poll_completion(mes, pipe,
&mes_remove_queue_pkt, sizeof(mes_remove_queue_pkt),
@@ -888,10 +1090,16 @@ static int mes_v12_0_reset_hw_queue(struct amdgpu_mes *mes,
union MESAPI__RESET mes_reset_queue_pkt;
int pipe;
if (input->use_mmio)
return mes_v12_0_reset_queue_mmio(mes, input->queue_type,
input->me_id, input->pipe_id,
input->queue_id, input->vmid);
if (input->use_mmio) {
int r = mes_v12_0_reset_queue_mmio(mes, input->queue_type,
input->me_id, input->pipe_id,
input->queue_id, input->vmid);
if (r)
return mes_v12_0_reset_pipe_mmio(mes, input->queue_type,
input->me_id, input->pipe_id,
input->queue_id, input->vmid);
return 0;
}
memset(&mes_reset_queue_pkt, 0, sizeof(mes_reset_queue_pkt));
@@ -915,10 +1123,7 @@ static int mes_v12_0_reset_hw_queue(struct amdgpu_mes *mes,
mes_reset_queue_pkt.doorbell_offset = input->doorbell_offset;
}
if (input->is_kq)
pipe = AMDGPU_MES_KIQ_PIPE;
else
pipe = AMDGPU_MES_SCHED_PIPE;
pipe = AMDGPU_MES_SCHED_PIPE;
return mes_v12_0_submit_pkt_and_poll_completion(mes, pipe,
&mes_reset_queue_pkt, sizeof(mes_reset_queue_pkt),
@@ -1094,7 +1299,7 @@ static void mes_v12_0_enable(struct amdgpu_device *adev, bool enable)
if (enable) {
mutex_lock(&adev->srbm_mutex);
for (pipe = 0; pipe < AMDGPU_MAX_MES_PIPES; pipe++) {
soc21_grbm_select(adev, 3, pipe, 0, 0);
soc24_grbm_select(adev, 3, pipe, 0, 0);
if (amdgpu_mes_log_enable) {
u32 log_size = AMDGPU_MES_LOG_BUFFER_SIZE + AMDGPU_MES_MSCRATCH_SIZE;
/* In case uni mes is not enabled, only program for pipe 0 */
@@ -1133,7 +1338,7 @@ static void mes_v12_0_enable(struct amdgpu_device *adev, bool enable)
WREG32_SOC15(GC, 0, regCP_MES_CNTL, data);
}
soc21_grbm_select(adev, 0, 0, 0, 0);
soc24_grbm_select(adev, 0, 0, 0, 0);
mutex_unlock(&adev->srbm_mutex);
if (amdgpu_emu_mode)
@@ -1165,7 +1370,7 @@ static void mes_v12_0_set_ucode_start_addr(struct amdgpu_device *adev)
mutex_lock(&adev->srbm_mutex);
for (pipe = 0; pipe < AMDGPU_MAX_MES_PIPES; pipe++) {
/* me=3, queue=0 */
soc21_grbm_select(adev, 3, pipe, 0, 0);
soc24_grbm_select(adev, 3, pipe, 0, 0);
/* set ucode start address */
ucode_addr = adev->mes.uc_start_addr[pipe] >> 2;
@@ -1174,7 +1379,7 @@ static void mes_v12_0_set_ucode_start_addr(struct amdgpu_device *adev)
WREG32_SOC15(GC, 0, regCP_MES_PRGRM_CNTR_START_HI,
upper_32_bits(ucode_addr));
soc21_grbm_select(adev, 0, 0, 0, 0);
soc24_grbm_select(adev, 0, 0, 0, 0);
}
mutex_unlock(&adev->srbm_mutex);
}
@@ -1203,7 +1408,7 @@ static int mes_v12_0_load_microcode(struct amdgpu_device *adev,
mutex_lock(&adev->srbm_mutex);
/* me=3, pipe=0, queue=0 */
soc21_grbm_select(adev, 3, pipe, 0, 0);
soc24_grbm_select(adev, 3, pipe, 0, 0);
WREG32_SOC15(GC, 0, regCP_MES_IC_BASE_CNTL, 0);
@@ -1238,7 +1443,7 @@ static int mes_v12_0_load_microcode(struct amdgpu_device *adev,
WREG32_SOC15(GC, 0, regCP_MES_IC_OP_CNTL, data);
}
soc21_grbm_select(adev, 0, 0, 0, 0);
soc24_grbm_select(adev, 0, 0, 0, 0);
mutex_unlock(&adev->srbm_mutex);
return 0;
@@ -1385,7 +1590,7 @@ static void mes_v12_0_queue_init_register(struct amdgpu_ring *ring)
uint32_t data = 0;
mutex_lock(&adev->srbm_mutex);
soc21_grbm_select(adev, 3, ring->pipe, 0, 0);
soc24_grbm_select(adev, 3, ring->pipe, 0, 0);
/* set CP_HQD_VMID.VMID = 0. */
data = RREG32_SOC15(GC, 0, regCP_HQD_VMID);
@@ -1436,7 +1641,7 @@ static void mes_v12_0_queue_init_register(struct amdgpu_ring *ring)
/* set CP_HQD_ACTIVE.ACTIVE=1 */
WREG32_SOC15(GC, 0, regCP_HQD_ACTIVE, mqd->cp_hqd_active);
soc21_grbm_select(adev, 0, 0, 0, 0);
soc24_grbm_select(adev, 0, 0, 0, 0);
mutex_unlock(&adev->srbm_mutex);
}
@@ -1502,14 +1707,14 @@ static int mes_v12_0_queue_init(struct amdgpu_device *adev,
((pipe == AMDGPU_MES_KIQ_PIPE) && !adev->mes.kiq_version)) {
/* get MES scheduler/KIQ versions */
mutex_lock(&adev->srbm_mutex);
soc21_grbm_select(adev, 3, pipe, 0, 0);
soc24_grbm_select(adev, 3, pipe, 0, 0);
if (pipe == AMDGPU_MES_SCHED_PIPE)
adev->mes.sched_version = RREG32_SOC15(GC, 0, regCP_MES_GP3_LO);
else if (pipe == AMDGPU_MES_KIQ_PIPE && adev->enable_mes_kiq)
adev->mes.kiq_version = RREG32_SOC15(GC, 0, regCP_MES_GP3_LO);
soc21_grbm_select(adev, 0, 0, 0, 0);
soc24_grbm_select(adev, 0, 0, 0, 0);
mutex_unlock(&adev->srbm_mutex);
}
@@ -1697,7 +1902,7 @@ static void mes_v12_0_kiq_dequeue_sched(struct amdgpu_device *adev)
int i;
mutex_lock(&adev->srbm_mutex);
soc21_grbm_select(adev, 3, AMDGPU_MES_SCHED_PIPE, 0, 0);
soc24_grbm_select(adev, 3, AMDGPU_MES_SCHED_PIPE, 0, 0);
/* disable the queue if it's active */
if (RREG32_SOC15(GC, 0, regCP_HQD_ACTIVE) & 1) {
@@ -1721,7 +1926,7 @@ static void mes_v12_0_kiq_dequeue_sched(struct amdgpu_device *adev)
WREG32_SOC15(GC, 0, regCP_HQD_PQ_WPTR_HI, 0);
WREG32_SOC15(GC, 0, regCP_HQD_PQ_RPTR, 0);
soc21_grbm_select(adev, 0, 0, 0, 0);
soc24_grbm_select(adev, 0, 0, 0, 0);
mutex_unlock(&adev->srbm_mutex);
adev->mes.ring[0].sched.ready = false;

View File

@@ -362,6 +362,8 @@ static int mes_v12_1_remove_hw_queue(struct amdgpu_mes *mes,
mes_remove_queue_pkt.doorbell_offset = input->doorbell_offset;
mes_remove_queue_pkt.gang_context_addr = input->gang_context_addr;
mes_remove_queue_pkt.queue_type =
convert_to_mes_queue_type(input->queue_type);
return mes_v12_1_submit_pkt_and_poll_completion(mes,
xcc_id, AMDGPU_MES_SCHED_PIPE,
@@ -417,10 +419,15 @@ static int mes_v12_1_map_legacy_queue(struct amdgpu_mes *mes,
convert_to_mes_queue_type(input->queue_type);
mes_add_queue_pkt.map_legacy_kq = 1;
if (mes->adev->enable_uni_mes)
pipe = AMDGPU_MES_KIQ_PIPE;
else
if (mes->adev->enable_uni_mes) {
/* Keep scheduler queue on KIQ pipe; map all other kernel queues on sched pipe. */
if (input->queue_type == AMDGPU_RING_TYPE_MES)
pipe = AMDGPU_MES_KIQ_PIPE;
else
pipe = AMDGPU_MES_SCHED_PIPE;
} else {
pipe = AMDGPU_MES_SCHED_PIPE;
}
return mes_v12_1_submit_pkt_and_poll_completion(mes,
input->xcc_id, pipe,
@@ -457,10 +464,15 @@ static int mes_v12_1_unmap_legacy_queue(struct amdgpu_mes *mes,
convert_to_mes_queue_type(input->queue_type);
}
if (mes->adev->enable_uni_mes)
pipe = AMDGPU_MES_KIQ_PIPE;
else
if (mes->adev->enable_uni_mes) {
/* Keep scheduler queue on KIQ pipe; map all other kernel queues on sched pipe. */
if (input->queue_type == AMDGPU_RING_TYPE_MES)
pipe = AMDGPU_MES_KIQ_PIPE;
else
pipe = AMDGPU_MES_SCHED_PIPE;
} else {
pipe = AMDGPU_MES_SCHED_PIPE;
}
return mes_v12_1_submit_pkt_and_poll_completion(mes,
input->xcc_id, pipe,
@@ -2262,6 +2274,7 @@ static int mes_v12_1_test_queue(struct amdgpu_device *adev, int xcc_id,
remove_queue.xcc_id = xcc_id;
remove_queue.doorbell_offset = doorbell_idx;
remove_queue.gang_context_addr = add_queue.gang_context_addr;
remove_queue.queue_type = queue_type;
r = mes_v12_1_remove_hw_queue(&adev->mes, &remove_queue);
error:

View File

@@ -29,7 +29,6 @@
#include "soc15_common.h"
#include "soc15.h"
#include "amdgpu_ras.h"
#include "amdgpu_psp.h"
#define regVM_L2_CNTL3_DEFAULT 0x80100007
@@ -636,236 +635,8 @@ const struct amdgpu_mmhub_funcs mmhub_v1_8_funcs = {
.get_clockgating = mmhub_v1_8_get_clockgating,
};
static const struct amdgpu_ras_err_status_reg_entry mmhub_v1_8_ce_reg_list[] = {
{AMDGPU_RAS_REG_ENTRY(MMHUB, 0, regMMEA0_CE_ERR_STATUS_LO, regMMEA0_CE_ERR_STATUS_HI),
1, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "MMEA0"},
{AMDGPU_RAS_REG_ENTRY(MMHUB, 0, regMMEA1_CE_ERR_STATUS_LO, regMMEA1_CE_ERR_STATUS_HI),
1, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "MMEA1"},
{AMDGPU_RAS_REG_ENTRY(MMHUB, 0, regMMEA2_CE_ERR_STATUS_LO, regMMEA2_CE_ERR_STATUS_HI),
1, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "MMEA2"},
{AMDGPU_RAS_REG_ENTRY(MMHUB, 0, regMMEA3_CE_ERR_STATUS_LO, regMMEA3_CE_ERR_STATUS_HI),
1, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "MMEA3"},
{AMDGPU_RAS_REG_ENTRY(MMHUB, 0, regMMEA4_CE_ERR_STATUS_LO, regMMEA4_CE_ERR_STATUS_HI),
1, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "MMEA4"},
{AMDGPU_RAS_REG_ENTRY(MMHUB, 0, regMM_CANE_CE_ERR_STATUS_LO, regMM_CANE_CE_ERR_STATUS_HI),
1, 0, "MM_CANE"},
};
static const struct amdgpu_ras_err_status_reg_entry mmhub_v1_8_ue_reg_list[] = {
{AMDGPU_RAS_REG_ENTRY(MMHUB, 0, regMMEA0_UE_ERR_STATUS_LO, regMMEA0_UE_ERR_STATUS_HI),
1, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "MMEA0"},
{AMDGPU_RAS_REG_ENTRY(MMHUB, 0, regMMEA1_UE_ERR_STATUS_LO, regMMEA1_UE_ERR_STATUS_HI),
1, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "MMEA1"},
{AMDGPU_RAS_REG_ENTRY(MMHUB, 0, regMMEA2_UE_ERR_STATUS_LO, regMMEA2_UE_ERR_STATUS_HI),
1, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "MMEA2"},
{AMDGPU_RAS_REG_ENTRY(MMHUB, 0, regMMEA3_UE_ERR_STATUS_LO, regMMEA3_UE_ERR_STATUS_HI),
1, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "MMEA3"},
{AMDGPU_RAS_REG_ENTRY(MMHUB, 0, regMMEA4_UE_ERR_STATUS_LO, regMMEA4_UE_ERR_STATUS_HI),
1, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "MMEA4"},
{AMDGPU_RAS_REG_ENTRY(MMHUB, 0, regMM_CANE_UE_ERR_STATUS_LO, regMM_CANE_UE_ERR_STATUS_HI),
1, 0, "MM_CANE"},
};
static const struct amdgpu_ras_memory_id_entry mmhub_v1_8_ras_memory_list[] = {
{AMDGPU_MMHUB_WGMI_PAGEMEM, "MMEA_WGMI_PAGEMEM"},
{AMDGPU_MMHUB_RGMI_PAGEMEM, "MMEA_RGMI_PAGEMEM"},
{AMDGPU_MMHUB_WDRAM_PAGEMEM, "MMEA_WDRAM_PAGEMEM"},
{AMDGPU_MMHUB_RDRAM_PAGEMEM, "MMEA_RDRAM_PAGEMEM"},
{AMDGPU_MMHUB_WIO_CMDMEM, "MMEA_WIO_CMDMEM"},
{AMDGPU_MMHUB_RIO_CMDMEM, "MMEA_RIO_CMDMEM"},
{AMDGPU_MMHUB_WGMI_CMDMEM, "MMEA_WGMI_CMDMEM"},
{AMDGPU_MMHUB_RGMI_CMDMEM, "MMEA_RGMI_CMDMEM"},
{AMDGPU_MMHUB_WDRAM_CMDMEM, "MMEA_WDRAM_CMDMEM"},
{AMDGPU_MMHUB_RDRAM_CMDMEM, "MMEA_RDRAM_CMDMEM"},
{AMDGPU_MMHUB_MAM_DMEM0, "MMEA_MAM_DMEM0"},
{AMDGPU_MMHUB_MAM_DMEM1, "MMEA_MAM_DMEM1"},
{AMDGPU_MMHUB_MAM_DMEM2, "MMEA_MAM_DMEM2"},
{AMDGPU_MMHUB_MAM_DMEM3, "MMEA_MAM_DMEM3"},
{AMDGPU_MMHUB_WRET_TAGMEM, "MMEA_WRET_TAGMEM"},
{AMDGPU_MMHUB_RRET_TAGMEM, "MMEA_RRET_TAGMEM"},
{AMDGPU_MMHUB_WIO_DATAMEM, "MMEA_WIO_DATAMEM"},
{AMDGPU_MMHUB_WGMI_DATAMEM, "MMEA_WGMI_DATAMEM"},
{AMDGPU_MMHUB_WDRAM_DATAMEM, "MMEA_WDRAM_DATAMEM"},
};
static void mmhub_v1_8_inst_query_ras_error_count(struct amdgpu_device *adev,
uint32_t mmhub_inst,
void *ras_err_status)
{
struct ras_err_data *err_data = (struct ras_err_data *)ras_err_status;
unsigned long ue_count = 0, ce_count = 0;
/* NOTE: mmhub is converted by aid_mask and the range is 0-3,
* which can be used as die ID directly */
struct amdgpu_smuio_mcm_config_info mcm_info = {
.socket_id = adev->smuio.funcs->get_socket_id(adev),
.die_id = mmhub_inst,
};
amdgpu_ras_inst_query_ras_error_count(adev,
mmhub_v1_8_ce_reg_list,
ARRAY_SIZE(mmhub_v1_8_ce_reg_list),
mmhub_v1_8_ras_memory_list,
ARRAY_SIZE(mmhub_v1_8_ras_memory_list),
mmhub_inst,
AMDGPU_RAS_ERROR__SINGLE_CORRECTABLE,
&ce_count);
amdgpu_ras_inst_query_ras_error_count(adev,
mmhub_v1_8_ue_reg_list,
ARRAY_SIZE(mmhub_v1_8_ue_reg_list),
mmhub_v1_8_ras_memory_list,
ARRAY_SIZE(mmhub_v1_8_ras_memory_list),
mmhub_inst,
AMDGPU_RAS_ERROR__MULTI_UNCORRECTABLE,
&ue_count);
amdgpu_ras_error_statistic_ce_count(err_data, &mcm_info, ce_count);
amdgpu_ras_error_statistic_ue_count(err_data, &mcm_info, ue_count);
}
static void mmhub_v1_8_query_ras_error_count(struct amdgpu_device *adev,
void *ras_err_status)
{
uint32_t inst_mask;
uint32_t i;
if (!amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__MMHUB)) {
dev_warn(adev->dev, "MMHUB RAS is not supported\n");
return;
}
inst_mask = adev->aid_mask;
for_each_inst(i, inst_mask)
mmhub_v1_8_inst_query_ras_error_count(adev, i, ras_err_status);
}
static void mmhub_v1_8_inst_reset_ras_error_count(struct amdgpu_device *adev,
uint32_t mmhub_inst)
{
amdgpu_ras_inst_reset_ras_error_count(adev,
mmhub_v1_8_ce_reg_list,
ARRAY_SIZE(mmhub_v1_8_ce_reg_list),
mmhub_inst);
amdgpu_ras_inst_reset_ras_error_count(adev,
mmhub_v1_8_ue_reg_list,
ARRAY_SIZE(mmhub_v1_8_ue_reg_list),
mmhub_inst);
}
static void mmhub_v1_8_reset_ras_error_count(struct amdgpu_device *adev)
{
uint32_t inst_mask;
uint32_t i;
if (!amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__MMHUB)) {
dev_warn(adev->dev, "MMHUB RAS is not supported\n");
return;
}
inst_mask = adev->aid_mask;
for_each_inst(i, inst_mask)
mmhub_v1_8_inst_reset_ras_error_count(adev, i);
}
static const struct amdgpu_ras_block_hw_ops mmhub_v1_8_ras_hw_ops = {
.query_ras_error_count = mmhub_v1_8_query_ras_error_count,
.reset_ras_error_count = mmhub_v1_8_reset_ras_error_count,
};
static int mmhub_v1_8_aca_bank_parser(struct aca_handle *handle, struct aca_bank *bank,
enum aca_smu_type type, void *data)
{
struct aca_bank_info info;
u64 misc0;
int ret;
ret = aca_bank_info_decode(bank, &info);
if (ret)
return ret;
misc0 = bank->regs[ACA_REG_IDX_MISC0];
switch (type) {
case ACA_SMU_TYPE_UE:
bank->aca_err_type = ACA_ERROR_TYPE_UE;
ret = aca_error_cache_log_bank_error(handle, &info, ACA_ERROR_TYPE_UE,
1ULL);
break;
case ACA_SMU_TYPE_CE:
bank->aca_err_type = ACA_ERROR_TYPE_CE;
ret = aca_error_cache_log_bank_error(handle, &info, bank->aca_err_type,
ACA_REG__MISC0__ERRCNT(misc0));
break;
default:
return -EINVAL;
}
return ret;
}
/* reference to smu driver if header file */
static int mmhub_v1_8_err_codes[] = {
0, 1, 2, 3, 4, /* CODE_DAGB0 - 4 */
5, 6, 7, 8, 9, /* CODE_EA0 - 4 */
10, /* CODE_UTCL2_ROUTER */
11, /* CODE_VML2 */
12, /* CODE_VML2_WALKER */
13, /* CODE_MMCANE */
};
static bool mmhub_v1_8_aca_bank_is_valid(struct aca_handle *handle, struct aca_bank *bank,
enum aca_smu_type type, void *data)
{
u32 instlo;
instlo = ACA_REG__IPID__INSTANCEIDLO(bank->regs[ACA_REG_IDX_IPID]);
instlo &= GENMASK(31, 1);
if (instlo != mmSMNAID_AID0_MCA_SMU)
return false;
if (aca_bank_check_error_codes(handle->adev, bank,
mmhub_v1_8_err_codes,
ARRAY_SIZE(mmhub_v1_8_err_codes)))
return false;
return true;
}
static const struct aca_bank_ops mmhub_v1_8_aca_bank_ops = {
.aca_bank_parser = mmhub_v1_8_aca_bank_parser,
.aca_bank_is_valid = mmhub_v1_8_aca_bank_is_valid,
};
static const struct aca_info mmhub_v1_8_aca_info = {
.hwip = ACA_HWIP_TYPE_SMU,
.mask = ACA_ERROR_UE_MASK,
.bank_ops = &mmhub_v1_8_aca_bank_ops,
};
static int mmhub_v1_8_ras_late_init(struct amdgpu_device *adev, struct ras_common_if *ras_block)
{
int r;
r = amdgpu_ras_block_late_init(adev, ras_block);
if (r)
return r;
r = amdgpu_ras_bind_aca(adev, AMDGPU_RAS_BLOCK__MMHUB,
&mmhub_v1_8_aca_info, NULL);
if (r)
goto late_fini;
return 0;
late_fini:
amdgpu_ras_block_late_fini(adev, ras_block);
return r;
}
struct amdgpu_mmhub_ras mmhub_v1_8_ras = {
.ras_block = {
.hw_ops = &mmhub_v1_8_ras_hw_ops,
.ras_late_init = mmhub_v1_8_ras_late_init,
.hw_ops = NULL,
},
};

View File

@@ -507,11 +507,6 @@ void nv_set_virt_ops(struct amdgpu_device *adev)
adev->virt.ops = &xgpu_nv_virt_ops;
}
static bool nv_need_full_reset(struct amdgpu_device *adev)
{
return true;
}
static bool nv_need_reset_on_init(struct amdgpu_device *adev)
{
u32 sol_reg;
@@ -595,7 +590,6 @@ static const struct amdgpu_asic_funcs nv_asic_funcs = {
.set_vce_clocks = &nv_set_vce_clocks,
.get_config_memsize = &nv_get_config_memsize,
.init_doorbell_index = &nv_init_doorbell_index,
.need_full_reset = &nv_need_full_reset,
.need_reset_on_init = &nv_need_reset_on_init,
.get_pcie_replay_count = &amdgpu_nbio_get_pcie_replay_count,
.supports_baco = &amdgpu_dpm_is_baco_supported,

View File

@@ -1237,65 +1237,6 @@ static int sdma_v3_0_wait_for_idle(struct amdgpu_ip_block *ip_block)
return -ETIMEDOUT;
}
static bool sdma_v3_0_check_soft_reset(struct amdgpu_ip_block *ip_block)
{
struct amdgpu_device *adev = ip_block->adev;
u32 srbm_soft_reset = 0;
u32 tmp = RREG32(mmSRBM_STATUS2);
if ((tmp & SRBM_STATUS2__SDMA_BUSY_MASK) ||
(tmp & SRBM_STATUS2__SDMA1_BUSY_MASK)) {
srbm_soft_reset |= SRBM_SOFT_RESET__SOFT_RESET_SDMA_MASK;
srbm_soft_reset |= SRBM_SOFT_RESET__SOFT_RESET_SDMA1_MASK;
}
if (srbm_soft_reset) {
adev->sdma.srbm_soft_reset = srbm_soft_reset;
return true;
} else {
adev->sdma.srbm_soft_reset = 0;
return false;
}
}
static int sdma_v3_0_pre_soft_reset(struct amdgpu_ip_block *ip_block)
{
struct amdgpu_device *adev = ip_block->adev;
u32 srbm_soft_reset = 0;
if (!adev->sdma.srbm_soft_reset)
return 0;
srbm_soft_reset = adev->sdma.srbm_soft_reset;
if (REG_GET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_SDMA) ||
REG_GET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_SDMA1)) {
sdma_v3_0_ctx_switch_enable(adev, false);
sdma_v3_0_enable(adev, false);
}
return 0;
}
static int sdma_v3_0_post_soft_reset(struct amdgpu_ip_block *ip_block)
{
struct amdgpu_device *adev = ip_block->adev;
u32 srbm_soft_reset = 0;
if (!adev->sdma.srbm_soft_reset)
return 0;
srbm_soft_reset = adev->sdma.srbm_soft_reset;
if (REG_GET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_SDMA) ||
REG_GET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_SDMA1)) {
sdma_v3_0_gfx_resume(adev);
sdma_v3_0_rlc_resume(adev);
}
return 0;
}
static int sdma_v3_0_soft_reset(struct amdgpu_ip_block *ip_block)
{
struct amdgpu_device *adev = ip_block->adev;
@@ -1552,9 +1493,6 @@ static const struct amd_ip_funcs sdma_v3_0_ip_funcs = {
.resume = sdma_v3_0_resume,
.is_idle = sdma_v3_0_is_idle,
.wait_for_idle = sdma_v3_0_wait_for_idle,
.check_soft_reset = sdma_v3_0_check_soft_reset,
.pre_soft_reset = sdma_v3_0_pre_soft_reset,
.post_soft_reset = sdma_v3_0_post_soft_reset,
.soft_reset = sdma_v3_0_soft_reset,
.set_clockgating_state = sdma_v3_0_set_clockgating_state,
.set_powergating_state = sdma_v3_0_set_powergating_state,

View File

@@ -95,8 +95,6 @@ static const struct amdgpu_hwip_reg_entry sdma_reg_list_4_4_2[] = {
SOC15_REG_ENTRY_STR(GC, 0, regSDMA_VM_CNTL)
};
#define mmSMNAID_AID0_MCA_SMU 0x03b30400
#define WREG32_SDMA(instance, offset, value) \
WREG32(sdma_v4_4_2_get_reg_offset(adev, (instance), (offset)), value)
#define RREG32_SDMA(instance, offset) \
@@ -1359,6 +1357,19 @@ static int sdma_v4_4_2_early_init(struct amdgpu_ip_block *ip_block)
struct amdgpu_device *adev = ip_block->adev;
int r;
switch (amdgpu_user_queue) {
case -1:
case 0:
default:
adev->sdma.no_user_submission = false;
adev->sdma.disable_uq = true;
break;
case 2:
adev->sdma.no_user_submission = true;
adev->sdma.disable_uq = true;
break;
}
r = sdma_v4_4_2_init_microcode(adev);
if (r)
return r;
@@ -1478,6 +1489,7 @@ static int sdma_v4_4_2_sw_init(struct amdgpu_ip_block *ip_block)
/* doorbell size is 2 dwords, get DWORD offset */
ring->doorbell_index = adev->doorbell_index.sdma_engine[i] << 1;
ring->vm_hub = AMDGPU_MMHUB0(aid_id);
ring->no_user_submission = adev->sdma.no_user_submission;
sprintf(ring->name, "sdma%d.%d", aid_id,
i % adev->sdma.num_inst_per_aid);
@@ -2404,187 +2416,9 @@ struct amdgpu_xcp_ip_funcs sdma_v4_4_2_xcp_funcs = {
.resume = &sdma_v4_4_2_xcp_resume
};
static const struct amdgpu_ras_err_status_reg_entry sdma_v4_2_2_ue_reg_list[] = {
{AMDGPU_RAS_REG_ENTRY(SDMA0, 0, regSDMA_UE_ERR_STATUS_LO, regSDMA_UE_ERR_STATUS_HI),
1, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "SDMA"},
};
static const struct amdgpu_ras_memory_id_entry sdma_v4_4_2_ras_memory_list[] = {
{AMDGPU_SDMA_MBANK_DATA_BUF0, "SDMA_MBANK_DATA_BUF0"},
{AMDGPU_SDMA_MBANK_DATA_BUF1, "SDMA_MBANK_DATA_BUF1"},
{AMDGPU_SDMA_MBANK_DATA_BUF2, "SDMA_MBANK_DATA_BUF2"},
{AMDGPU_SDMA_MBANK_DATA_BUF3, "SDMA_MBANK_DATA_BUF3"},
{AMDGPU_SDMA_MBANK_DATA_BUF4, "SDMA_MBANK_DATA_BUF4"},
{AMDGPU_SDMA_MBANK_DATA_BUF5, "SDMA_MBANK_DATA_BUF5"},
{AMDGPU_SDMA_MBANK_DATA_BUF6, "SDMA_MBANK_DATA_BUF6"},
{AMDGPU_SDMA_MBANK_DATA_BUF7, "SDMA_MBANK_DATA_BUF7"},
{AMDGPU_SDMA_MBANK_DATA_BUF8, "SDMA_MBANK_DATA_BUF8"},
{AMDGPU_SDMA_MBANK_DATA_BUF9, "SDMA_MBANK_DATA_BUF9"},
{AMDGPU_SDMA_MBANK_DATA_BUF10, "SDMA_MBANK_DATA_BUF10"},
{AMDGPU_SDMA_MBANK_DATA_BUF11, "SDMA_MBANK_DATA_BUF11"},
{AMDGPU_SDMA_MBANK_DATA_BUF12, "SDMA_MBANK_DATA_BUF12"},
{AMDGPU_SDMA_MBANK_DATA_BUF13, "SDMA_MBANK_DATA_BUF13"},
{AMDGPU_SDMA_MBANK_DATA_BUF14, "SDMA_MBANK_DATA_BUF14"},
{AMDGPU_SDMA_MBANK_DATA_BUF15, "SDMA_MBANK_DATA_BUF15"},
{AMDGPU_SDMA_UCODE_BUF, "SDMA_UCODE_BUF"},
{AMDGPU_SDMA_RB_CMD_BUF, "SDMA_RB_CMD_BUF"},
{AMDGPU_SDMA_IB_CMD_BUF, "SDMA_IB_CMD_BUF"},
{AMDGPU_SDMA_UTCL1_RD_FIFO, "SDMA_UTCL1_RD_FIFO"},
{AMDGPU_SDMA_UTCL1_RDBST_FIFO, "SDMA_UTCL1_RDBST_FIFO"},
{AMDGPU_SDMA_UTCL1_WR_FIFO, "SDMA_UTCL1_WR_FIFO"},
{AMDGPU_SDMA_DATA_LUT_FIFO, "SDMA_DATA_LUT_FIFO"},
{AMDGPU_SDMA_SPLIT_DAT_BUF, "SDMA_SPLIT_DAT_BUF"},
};
static void sdma_v4_4_2_inst_query_ras_error_count(struct amdgpu_device *adev,
uint32_t sdma_inst,
void *ras_err_status)
{
struct ras_err_data *err_data = (struct ras_err_data *)ras_err_status;
uint32_t sdma_dev_inst = GET_INST(SDMA0, sdma_inst);
unsigned long ue_count = 0;
struct amdgpu_smuio_mcm_config_info mcm_info = {
.socket_id = adev->smuio.funcs->get_socket_id(adev),
.die_id = adev->sdma.instance[sdma_inst].aid_id,
};
/* sdma v4_4_2 doesn't support query ce counts */
amdgpu_ras_inst_query_ras_error_count(adev,
sdma_v4_2_2_ue_reg_list,
ARRAY_SIZE(sdma_v4_2_2_ue_reg_list),
sdma_v4_4_2_ras_memory_list,
ARRAY_SIZE(sdma_v4_4_2_ras_memory_list),
sdma_dev_inst,
AMDGPU_RAS_ERROR__MULTI_UNCORRECTABLE,
&ue_count);
amdgpu_ras_error_statistic_ue_count(err_data, &mcm_info, ue_count);
}
static void sdma_v4_4_2_query_ras_error_count(struct amdgpu_device *adev,
void *ras_err_status)
{
uint32_t inst_mask;
int i = 0;
inst_mask = GENMASK(adev->sdma.num_instances - 1, 0);
if (amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__SDMA)) {
for_each_inst(i, inst_mask)
sdma_v4_4_2_inst_query_ras_error_count(adev, i, ras_err_status);
} else {
dev_warn(adev->dev, "SDMA RAS is not supported\n");
}
}
static void sdma_v4_4_2_inst_reset_ras_error_count(struct amdgpu_device *adev,
uint32_t sdma_inst)
{
uint32_t sdma_dev_inst = GET_INST(SDMA0, sdma_inst);
amdgpu_ras_inst_reset_ras_error_count(adev,
sdma_v4_2_2_ue_reg_list,
ARRAY_SIZE(sdma_v4_2_2_ue_reg_list),
sdma_dev_inst);
}
static void sdma_v4_4_2_reset_ras_error_count(struct amdgpu_device *adev)
{
uint32_t inst_mask;
int i = 0;
inst_mask = GENMASK(adev->sdma.num_instances - 1, 0);
if (amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__SDMA)) {
for_each_inst(i, inst_mask)
sdma_v4_4_2_inst_reset_ras_error_count(adev, i);
} else {
dev_warn(adev->dev, "SDMA RAS is not supported\n");
}
}
static const struct amdgpu_ras_block_hw_ops sdma_v4_4_2_ras_hw_ops = {
.query_ras_error_count = sdma_v4_4_2_query_ras_error_count,
.reset_ras_error_count = sdma_v4_4_2_reset_ras_error_count,
};
static int sdma_v4_4_2_aca_bank_parser(struct aca_handle *handle, struct aca_bank *bank,
enum aca_smu_type type, void *data)
{
struct aca_bank_info info;
u64 misc0;
int ret;
ret = aca_bank_info_decode(bank, &info);
if (ret)
return ret;
misc0 = bank->regs[ACA_REG_IDX_MISC0];
switch (type) {
case ACA_SMU_TYPE_UE:
bank->aca_err_type = ACA_ERROR_TYPE_UE;
ret = aca_error_cache_log_bank_error(handle, &info, ACA_ERROR_TYPE_UE,
1ULL);
break;
case ACA_SMU_TYPE_CE:
bank->aca_err_type = ACA_ERROR_TYPE_CE;
ret = aca_error_cache_log_bank_error(handle, &info, bank->aca_err_type,
ACA_REG__MISC0__ERRCNT(misc0));
break;
default:
return -EINVAL;
}
return ret;
}
/* CODE_SDMA0 - CODE_SDMA4, reference to smu driver if header file */
static int sdma_v4_4_2_err_codes[] = { 33, 34, 35, 36 };
static bool sdma_v4_4_2_aca_bank_is_valid(struct aca_handle *handle, struct aca_bank *bank,
enum aca_smu_type type, void *data)
{
u32 instlo;
instlo = ACA_REG__IPID__INSTANCEIDLO(bank->regs[ACA_REG_IDX_IPID]);
instlo &= GENMASK(31, 1);
if (instlo != mmSMNAID_AID0_MCA_SMU)
return false;
if (aca_bank_check_error_codes(handle->adev, bank,
sdma_v4_4_2_err_codes,
ARRAY_SIZE(sdma_v4_4_2_err_codes)))
return false;
return true;
}
static const struct aca_bank_ops sdma_v4_4_2_aca_bank_ops = {
.aca_bank_parser = sdma_v4_4_2_aca_bank_parser,
.aca_bank_is_valid = sdma_v4_4_2_aca_bank_is_valid,
};
static const struct aca_info sdma_v4_4_2_aca_info = {
.hwip = ACA_HWIP_TYPE_SMU,
.mask = ACA_ERROR_UE_MASK,
.bank_ops = &sdma_v4_4_2_aca_bank_ops,
};
static int sdma_v4_4_2_ras_late_init(struct amdgpu_device *adev, struct ras_common_if *ras_block)
{
int r;
r = amdgpu_sdma_ras_late_init(adev, ras_block);
if (r)
return r;
return amdgpu_ras_bind_aca(adev, AMDGPU_RAS_BLOCK__SDMA,
&sdma_v4_4_2_aca_info, NULL);
}
static struct amdgpu_sdma_ras sdma_v4_4_2_ras = {
.ras_block = {
.hw_ops = &sdma_v4_4_2_ras_hw_ops,
.ras_late_init = sdma_v4_4_2_ras_late_init,
.hw_ops = NULL,
},
};

View File

@@ -793,23 +793,6 @@ static int sdma_v6_0_soft_reset(struct amdgpu_ip_block *ip_block)
return sdma_v6_0_start(adev);
}
static bool sdma_v6_0_check_soft_reset(struct amdgpu_ip_block *ip_block)
{
struct amdgpu_device *adev = ip_block->adev;
struct amdgpu_ring *ring;
int i, r;
long tmo = msecs_to_jiffies(1000);
for (i = 0; i < adev->sdma.num_instances; i++) {
ring = &adev->sdma.instance[i].ring;
r = amdgpu_ring_test_ib(ring, tmo);
if (r)
return true;
}
return false;
}
/**
* sdma_v6_0_start - setup and start the async dma engines
*
@@ -1747,7 +1730,6 @@ const struct amd_ip_funcs sdma_v6_0_ip_funcs = {
.is_idle = sdma_v6_0_is_idle,
.wait_for_idle = sdma_v6_0_wait_for_idle,
.soft_reset = sdma_v6_0_soft_reset,
.check_soft_reset = sdma_v6_0_check_soft_reset,
.set_clockgating_state = sdma_v6_0_set_clockgating_state,
.set_powergating_state = sdma_v6_0_set_powergating_state,
.get_clockgating_state = sdma_v6_0_get_clockgating_state,

View File

@@ -784,23 +784,6 @@ static int sdma_v7_0_soft_reset(struct amdgpu_ip_block *ip_block)
return sdma_v7_0_start(adev);
}
static bool sdma_v7_0_check_soft_reset(struct amdgpu_ip_block *ip_block)
{
struct amdgpu_device *adev = ip_block->adev;
struct amdgpu_ring *ring;
int i, r;
long tmo = msecs_to_jiffies(1000);
for (i = 0; i < adev->sdma.num_instances; i++) {
ring = &adev->sdma.instance[i].ring;
r = amdgpu_ring_test_ib(ring, tmo);
if (r)
return true;
}
return false;
}
static int sdma_v7_0_reset_queue(struct amdgpu_ring *ring,
unsigned int vmid,
struct amdgpu_fence *timedout_fence)
@@ -1679,7 +1662,6 @@ const struct amd_ip_funcs sdma_v7_0_ip_funcs = {
.is_idle = sdma_v7_0_is_idle,
.wait_for_idle = sdma_v7_0_wait_for_idle,
.soft_reset = sdma_v7_0_soft_reset,
.check_soft_reset = sdma_v7_0_check_soft_reset,
.set_clockgating_state = sdma_v7_0_set_clockgating_state,
.set_powergating_state = sdma_v7_0_set_powergating_state,
.get_clockgating_state = sdma_v7_0_get_clockgating_state,

View File

@@ -775,23 +775,6 @@ static int sdma_v7_1_soft_reset(struct amdgpu_ip_block *ip_block)
return sdma_v7_1_inst_start(adev, inst_mask);
}
static bool sdma_v7_1_check_soft_reset(struct amdgpu_ip_block *ip_block)
{
struct amdgpu_device *adev = ip_block->adev;
struct amdgpu_ring *ring;
int i, r;
long tmo = msecs_to_jiffies(1000);
for (i = 0; i < adev->sdma.num_instances; i++) {
ring = &adev->sdma.instance[i].ring;
r = amdgpu_ring_test_ib(ring, tmo);
if (r)
return true;
}
return false;
}
static int sdma_v7_1_reset_queue(struct amdgpu_ring *ring,
unsigned int vmid,
struct amdgpu_fence *timedout_fence)
@@ -1644,7 +1627,6 @@ const struct amd_ip_funcs sdma_v7_1_ip_funcs = {
.is_idle = sdma_v7_1_is_idle,
.wait_for_idle = sdma_v7_1_wait_for_idle,
.soft_reset = sdma_v7_1_soft_reset,
.check_soft_reset = sdma_v7_1_check_soft_reset,
.set_clockgating_state = sdma_v7_1_set_clockgating_state,
.set_powergating_state = sdma_v7_1_set_powergating_state,
.get_clockgating_state = sdma_v7_1_get_clockgating_state,

View File

@@ -1509,12 +1509,6 @@ static void si_invalidate_hdp(struct amdgpu_device *adev,
}
}
static bool si_need_full_reset(struct amdgpu_device *adev)
{
/* change this when we support soft reset */
return true;
}
static bool si_need_reset_on_init(struct amdgpu_device *adev)
{
return false;
@@ -2019,7 +2013,6 @@ static const struct amdgpu_asic_funcs si_asic_funcs =
.get_config_memsize = &si_get_config_memsize,
.flush_hdp = &si_flush_hdp,
.invalidate_hdp = &si_invalidate_hdp,
.need_full_reset = &si_need_full_reset,
.get_pcie_usage = &si_get_pcie_usage,
.need_reset_on_init = &si_need_reset_on_init,
.get_pcie_replay_count = &si_get_pcie_replay_count,

Some files were not shown because too many files have changed in this diff Show More