Skip to content

Commit 28083ff

Browse files
committed
accel/ivpu: Fix DevTLB errors on suspend/resume and recovery
Issue IP reset before shutdown in order to complete all upstream requests to the SOC. Without this DevTLB is complaining about incomplete transactions and NPU cannot resume from suspend. This problem is only happening on recent IFWI releases. IP reset in rare corner cases can mess up PCI configuration, so save it before the reset. After this happens it is also impossible to issue PLL requests and D0->D3->D0 cycle is needed to recover the NPU. Add WP 0 request on power up, so the PUNIT is always notified about NPU reset. Use D0/D3 cycle for recovery as it can recover from failed IP reset and FLR cannot. Fixes: 3f7c063 ("accel/ivpu/37xx: Fix hangs related to MMIO reset") Signed-off-by: Jacek Lawrynowicz <[email protected]> Reviewed-by: Jeffrey Hugo <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
1 parent 5f8408a commit 28083ff

File tree

2 files changed

+54
-29
lines changed

2 files changed

+54
-29
lines changed

drivers/accel/ivpu/ivpu_hw_37xx.c

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -510,16 +510,6 @@ static int ivpu_boot_pwr_domain_enable(struct ivpu_device *vdev)
510510
return ret;
511511
}
512512

513-
static int ivpu_boot_pwr_domain_disable(struct ivpu_device *vdev)
514-
{
515-
ivpu_boot_dpu_active_drive(vdev, false);
516-
ivpu_boot_pwr_island_isolation_drive(vdev, true);
517-
ivpu_boot_pwr_island_trickle_drive(vdev, false);
518-
ivpu_boot_pwr_island_drive(vdev, false);
519-
520-
return ivpu_boot_wait_for_pwr_island_status(vdev, 0x0);
521-
}
522-
523513
static void ivpu_boot_no_snoop_enable(struct ivpu_device *vdev)
524514
{
525515
u32 val = REGV_RD32(VPU_37XX_HOST_IF_TCU_PTW_OVERRIDES);
@@ -616,12 +606,37 @@ static int ivpu_hw_37xx_info_init(struct ivpu_device *vdev)
616606
return 0;
617607
}
618608

609+
static int ivpu_hw_37xx_ip_reset(struct ivpu_device *vdev)
610+
{
611+
int ret;
612+
u32 val;
613+
614+
if (IVPU_WA(punit_disabled))
615+
return 0;
616+
617+
ret = REGB_POLL_FLD(VPU_37XX_BUTTRESS_VPU_IP_RESET, TRIGGER, 0, TIMEOUT_US);
618+
if (ret) {
619+
ivpu_err(vdev, "Timed out waiting for TRIGGER bit\n");
620+
return ret;
621+
}
622+
623+
val = REGB_RD32(VPU_37XX_BUTTRESS_VPU_IP_RESET);
624+
val = REG_SET_FLD(VPU_37XX_BUTTRESS_VPU_IP_RESET, TRIGGER, val);
625+
REGB_WR32(VPU_37XX_BUTTRESS_VPU_IP_RESET, val);
626+
627+
ret = REGB_POLL_FLD(VPU_37XX_BUTTRESS_VPU_IP_RESET, TRIGGER, 0, TIMEOUT_US);
628+
if (ret)
629+
ivpu_err(vdev, "Timed out waiting for RESET completion\n");
630+
631+
return ret;
632+
}
633+
619634
static int ivpu_hw_37xx_reset(struct ivpu_device *vdev)
620635
{
621636
int ret = 0;
622637

623-
if (ivpu_boot_pwr_domain_disable(vdev)) {
624-
ivpu_err(vdev, "Failed to disable power domain\n");
638+
if (ivpu_hw_37xx_ip_reset(vdev)) {
639+
ivpu_err(vdev, "Failed to reset NPU\n");
625640
ret = -EIO;
626641
}
627642

@@ -661,6 +676,11 @@ static int ivpu_hw_37xx_power_up(struct ivpu_device *vdev)
661676
{
662677
int ret;
663678

679+
/* PLL requests may fail when powering down, so issue WP 0 here */
680+
ret = ivpu_pll_disable(vdev);
681+
if (ret)
682+
ivpu_warn(vdev, "Failed to disable PLL: %d\n", ret);
683+
664684
ret = ivpu_hw_37xx_d0i3_disable(vdev);
665685
if (ret)
666686
ivpu_warn(vdev, "Failed to disable D0I3: %d\n", ret);

drivers/accel/ivpu/ivpu_pm.c

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,14 @@ static int ivpu_suspend(struct ivpu_device *vdev)
5858
{
5959
int ret;
6060

61+
/* Save PCI state before powering down as it sometimes gets corrupted if NPU hangs */
62+
pci_save_state(to_pci_dev(vdev->drm.dev));
63+
6164
ret = ivpu_shutdown(vdev);
62-
if (ret) {
65+
if (ret)
6366
ivpu_err(vdev, "Failed to shutdown VPU: %d\n", ret);
64-
return ret;
65-
}
67+
68+
pci_set_power_state(to_pci_dev(vdev->drm.dev), PCI_D3hot);
6669

6770
return ret;
6871
}
@@ -71,6 +74,9 @@ static int ivpu_resume(struct ivpu_device *vdev)
7174
{
7275
int ret;
7376

77+
pci_set_power_state(to_pci_dev(vdev->drm.dev), PCI_D0);
78+
pci_restore_state(to_pci_dev(vdev->drm.dev));
79+
7480
retry:
7581
ret = ivpu_hw_power_up(vdev);
7682
if (ret) {
@@ -120,15 +126,20 @@ static void ivpu_pm_recovery_work(struct work_struct *work)
120126

121127
ivpu_fw_log_dump(vdev);
122128

123-
retry:
124-
ret = pci_try_reset_function(to_pci_dev(vdev->drm.dev));
125-
if (ret == -EAGAIN && !drm_dev_is_unplugged(&vdev->drm)) {
126-
cond_resched();
127-
goto retry;
128-
}
129+
atomic_inc(&vdev->pm->reset_counter);
130+
atomic_set(&vdev->pm->reset_pending, 1);
131+
down_write(&vdev->pm->reset_lock);
132+
133+
ivpu_suspend(vdev);
134+
ivpu_pm_prepare_cold_boot(vdev);
135+
ivpu_jobs_abort_all(vdev);
136+
137+
ret = ivpu_resume(vdev);
138+
if (ret)
139+
ivpu_err(vdev, "Failed to resume NPU: %d\n", ret);
129140

130-
if (ret && ret != -EAGAIN)
131-
ivpu_err(vdev, "Failed to reset VPU: %d\n", ret);
141+
up_write(&vdev->pm->reset_lock);
142+
atomic_set(&vdev->pm->reset_pending, 0);
132143

133144
kobject_uevent_env(&vdev->drm.dev->kobj, KOBJ_CHANGE, evt);
134145
pm_runtime_mark_last_busy(vdev->drm.dev);
@@ -200,9 +211,6 @@ int ivpu_pm_suspend_cb(struct device *dev)
200211
ivpu_suspend(vdev);
201212
ivpu_pm_prepare_warm_boot(vdev);
202213

203-
pci_save_state(to_pci_dev(dev));
204-
pci_set_power_state(to_pci_dev(dev), PCI_D3hot);
205-
206214
ivpu_dbg(vdev, PM, "Suspend done.\n");
207215

208216
return 0;
@@ -216,9 +224,6 @@ int ivpu_pm_resume_cb(struct device *dev)
216224

217225
ivpu_dbg(vdev, PM, "Resume..\n");
218226

219-
pci_set_power_state(to_pci_dev(dev), PCI_D0);
220-
pci_restore_state(to_pci_dev(dev));
221-
222227
ret = ivpu_resume(vdev);
223228
if (ret)
224229
ivpu_err(vdev, "Failed to resume: %d\n", ret);

0 commit comments

Comments
 (0)