mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-30 22:54:17 -04:00
drm/amdgpu/gfx11: add priv-fault user-queue recovery worker
A gfx user-queue priv/bad-op fault is raised by the ME and carries only
the HW slot, not the faulting queue's doorbell. Add a per-IP worker that
drains adev->gfx.userq_priv_fault_slots, reads the doorbell back from each
HQD via soc21_grbm_select (regCP_RB_DOORBELL_CONTROL), looks up the user
queue and kicks its per-queue reset.
The shared amdgpu_gfx_handle_priv_fault() helper schedules this worker for
a gfx user-queue fault; wiring the helper up is done in a later patch.
v2:
- gate on adev->gfx.disable_uq instead of !adev->enable_mes (Alex)
- document why both the doorbell (compute) and HW-slot (gfx) reset
paths are needed (Alex)
v3:
- rebase amd-staging-drm-next. adapt to the commit 9243cf4777 ("drm/amd/amdgpu: remove duplicated code in gfx_v11 and gfx_v12"); no functional change
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Suggested-by: Mario Sopena-Novales <Mario.Novales@amd.com>
Signed-off-by: Jesse Zhang <Jesse.Zhang@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
committed by
Alex Deucher
parent
9ad81600b9
commit
2b1e74c07d
@@ -362,6 +362,7 @@ static void gfx_v11_0_ring_invalidate_tlbs(struct amdgpu_ring *ring,
|
||||
bool all_hub, uint8_t dst_sel);
|
||||
static void gfx_v11_0_set_safe_mode(struct amdgpu_device *adev, int xcc_id);
|
||||
static void gfx_v11_0_unset_safe_mode(struct amdgpu_device *adev, int xcc_id);
|
||||
static void gfx_v11_0_userq_priv_fault_work(struct work_struct *work);
|
||||
static void gfx_v11_0_update_perf_clk(struct amdgpu_device *adev,
|
||||
bool enable);
|
||||
|
||||
@@ -1932,6 +1933,8 @@ static int gfx_v11_0_sw_init(struct amdgpu_ip_block *ip_block)
|
||||
|
||||
mutex_init(&adev->gfx.mec.reset_mutex);
|
||||
|
||||
INIT_WORK(&adev->gfx.userq_priv_fault_work, gfx_v11_0_userq_priv_fault_work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1969,6 +1972,8 @@ static int gfx_v11_0_sw_fini(struct amdgpu_ip_block *ip_block)
|
||||
int i;
|
||||
struct amdgpu_device *adev = ip_block->adev;
|
||||
|
||||
cancel_work_sync(&adev->gfx.userq_priv_fault_work);
|
||||
|
||||
for (i = 0; i < adev->gfx.num_gfx_rings; i++)
|
||||
amdgpu_ring_fini(&adev->gfx.gfx_ring[i]);
|
||||
for (i = 0; i < adev->gfx.num_compute_rings; i++)
|
||||
@@ -6711,6 +6716,40 @@ static int gfx_v11_0_set_priv_inst_fault_state(struct amdgpu_device *adev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* A gfx exception IV carries no doorbell. For each faulted slot, read the
|
||||
* doorbell back from the HQD (left in place by the fatal fault), look up the
|
||||
* user queue and kick its per-queue reset.
|
||||
*/
|
||||
static void gfx_v11_0_userq_priv_fault_work(struct work_struct *work)
|
||||
{
|
||||
struct amdgpu_device *adev =
|
||||
container_of(work, struct amdgpu_device, gfx.userq_priv_fault_work);
|
||||
unsigned long slots = xchg(&adev->gfx.userq_priv_fault_slots, 0);
|
||||
unsigned int id;
|
||||
|
||||
for_each_set_bit(id, &slots, BITS_PER_LONG) {
|
||||
u8 pipe = id & 0x3;
|
||||
u8 queue = (id >> 2) & 0x7;
|
||||
struct amdgpu_usermode_queue *q;
|
||||
u32 db_ctrl, doorbell;
|
||||
|
||||
amdgpu_gfx_off_ctrl(adev, false);
|
||||
mutex_lock(&adev->srbm_mutex);
|
||||
soc21_grbm_select(adev, 0, pipe, queue, 0);
|
||||
db_ctrl = RREG32_SOC15(GC, 0, regCP_RB_DOORBELL_CONTROL);
|
||||
soc21_grbm_select(adev, 0, 0, 0, 0);
|
||||
mutex_unlock(&adev->srbm_mutex);
|
||||
amdgpu_gfx_off_ctrl(adev, true);
|
||||
|
||||
doorbell = (db_ctrl & CP_RB_DOORBELL_CONTROL__DOORBELL_OFFSET_MASK) >>
|
||||
CP_RB_DOORBELL_CONTROL__DOORBELL_OFFSET__SHIFT;
|
||||
q = xa_load(&adev->userq_doorbell_xa, doorbell);
|
||||
if (q)
|
||||
amdgpu_userq_start_hang_detect_work(q);
|
||||
}
|
||||
}
|
||||
|
||||
static void gfx_v11_0_handle_priv_fault(struct amdgpu_device *adev,
|
||||
struct amdgpu_iv_entry *entry)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user