vega10: implement PSP mode1 reset

When the GPU gets released, the guest driver halts the GPU's SMU.
On subsequent reset events, this module attempts a BACO reset
which requires a responsive SMU to enter BACO state.
With the SMU halted, PPSMC_MSG_EnterBaco times out and the BACO reset fails,
leaving the GPU in an unusable state until the host is rebooted.

Add a PSP (Platform Security Processor) Mode 1 Reset path for
Vega10.
This work the same way as this amdgpu kernel driver patch:
https://lists.freedesktop.org/archives/amd-gfx/2017-September/013203.html
and its inspired from the already implemented mode1 reset for Vega20.

Mode 1 Reset sends a hardware reset command (GFX_CTRL_CMD_ID_MODE1_RST)
directly to the PSP via the MP0_SMN_C2PMSG_64 mailbox register,
bypassing the unresponsive SMU entirely.

The Mode 1 Reset is attempted first in the reset sequence.
The existing BACO path is used as a fallback.

Tested on
AMD Radeon RX Vega 56 (device 0x687f)
Proxmox VE 9.2.2
kernel 7.0.2-6-pve

Confirmed that VMs can be started, stopped, and restarted repeatedly without
requiring a host reboot.
This commit is contained in:
oberdfr
2026-05-23 19:04:22 +02:00
committed by Geoffrey McRae
parent 31d17c5e11
commit 71eb4a6672
+53 -7
View File
@@ -30,6 +30,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA
#include "common.h" #include "common.h"
#include "compat.h" #include "compat.h"
#include "common_baco.h" #include "common_baco.h"
#include "psp_gfx_if.h"
/* MP Apertures, from smu9_smumgr.c */ /* MP Apertures, from smu9_smumgr.c */
#define MP0_Public 0x03800000 #define MP0_Public 0x03800000
@@ -126,6 +127,41 @@ int vega10_baco_set_state(struct amd_fake_dev *adev, enum BACO_STATE state)
return -EINVAL; return -EINVAL;
} }
static int amd_vega10_mode1_reset(struct amd_fake_dev *adev)
{
int ret, i;
uint32_t offset;
uint32_t pci_regs[128];
struct pci_dev *pdev = adev_to_amd_private(adev)->vdev->pdev;
offset = SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_64);
ret = psp_wait_for(adev, offset, 0x80000000, 0x8000FFFF, false);
if (ret) {
vr_warn(adev_to_amd_private(adev)->vdev,
"psp not working for mode1 reset\n");
return ret;
}
/* send mode 1 reset command to PSP */
WREG32(offset, GFX_CTRL_CMD_ID_MODE1_RST);
msleep(500);
/* check if PSP came back */
offset = SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_33);
ret = psp_wait_for(adev, offset, 0x80000000, 0x80000000, false);
if (ret) {
vr_warn(adev_to_amd_private(adev)->vdev,
"psp mode1 reset completed but PSP not responding\n");
return ret;
}
vr_info(adev_to_amd_private(adev)->vdev,
"psp mode1 reset succeeded\n");
return 0;
}
static int amd_vega10_reset(struct vendor_reset_dev *dev) static int amd_vega10_reset(struct vendor_reset_dev *dev)
{ {
struct amd_vendor_private *priv = amd_private(dev); struct amd_vendor_private *priv = amd_private(dev);
@@ -150,13 +186,6 @@ static int amd_vega10_reset(struct vendor_reset_dev *dev)
goto free_adev; goto free_adev;
} }
ret = atom_bios_init(adev);
if (ret)
{
vr_err(dev, "atom_bios_init failed: %d\n", ret);
goto free_adev;
}
/* it's important we wait for the SOC to be ready */ /* it's important we wait for the SOC to be ready */
for (timeout = 100000; timeout; --timeout) for (timeout = 100000; timeout; --timeout)
{ {
@@ -183,6 +212,23 @@ static int amd_vega10_reset(struct vendor_reset_dev *dev)
psp_bl_ready ? "yes" : "no", psp_bl_ready ? "yes" : "no",
baco_state == BACO_STATE_IN ? "on" : "off"); baco_state == BACO_STATE_IN ? "on" : "off");
/* Try PSP Mode 1 Reset first. Preferred when the SMU is unresponsive */
ret = amd_vega10_mode1_reset(adev);
if (!ret)
{
vr_info(dev, "mode1 reset succeeded, skipping BACO\n");
goto free_adev;
}
vr_info(dev, "mode1 reset failed, falling back to BACO\n");
ret = atom_bios_init(adev);
if (ret)
{
vr_err(dev, "atom_bios_init failed: %d\n", ret);
goto free_adev;
}
if (sol == ~1L && baco_state != BACO_STATE_IN) if (sol == ~1L && baco_state != BACO_STATE_IN)
{ {
vr_warn(dev, "timed out waiting for SOL to be valid\n"); vr_warn(dev, "timed out waiting for SOL to be valid\n");