[PATCH] accel/ivpu: Fix DevTLB errors on suspend/resume
Jacek Lawrynowicz
jacek.lawrynowicz at linux.intel.com
Mon Feb 12 08:02:12 UTC 2024
Applied to drm-misc-fixes
On 06.02.2024 16:19, Jacek Lawrynowicz wrote:
> 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.
>
> Fixes: 3f7c0634926d ("accel/ivpu/37xx: Fix hangs related to MMIO reset")
> Signed-off-by: Jacek Lawrynowicz <jacek.lawrynowicz at linux.intel.com>
> ---
> drivers/accel/ivpu/ivpu_hw_37xx.c | 44 ++++++++++++++++++++++---------
> drivers/accel/ivpu/ivpu_pm.c | 12 ++++-----
> 2 files changed, 38 insertions(+), 18 deletions(-)
>
> diff --git a/drivers/accel/ivpu/ivpu_hw_37xx.c b/drivers/accel/ivpu/ivpu_hw_37xx.c
> index 77accd029c4a..89af1006df55 100644
> --- a/drivers/accel/ivpu/ivpu_hw_37xx.c
> +++ b/drivers/accel/ivpu/ivpu_hw_37xx.c
> @@ -510,16 +510,6 @@ static int ivpu_boot_pwr_domain_enable(struct ivpu_device *vdev)
> return ret;
> }
>
> -static int ivpu_boot_pwr_domain_disable(struct ivpu_device *vdev)
> -{
> - ivpu_boot_dpu_active_drive(vdev, false);
> - ivpu_boot_pwr_island_isolation_drive(vdev, true);
> - ivpu_boot_pwr_island_trickle_drive(vdev, false);
> - ivpu_boot_pwr_island_drive(vdev, false);
> -
> - return ivpu_boot_wait_for_pwr_island_status(vdev, 0x0);
> -}
> -
> static void ivpu_boot_no_snoop_enable(struct ivpu_device *vdev)
> {
> 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)
> return 0;
> }
>
> +static int ivpu_hw_37xx_ip_reset(struct ivpu_device *vdev)
> +{
> + int ret;
> + u32 val;
> +
> + if (IVPU_WA(punit_disabled))
> + return 0;
> +
> + ret = REGB_POLL_FLD(VPU_37XX_BUTTRESS_VPU_IP_RESET, TRIGGER, 0, TIMEOUT_US);
> + if (ret) {
> + ivpu_err(vdev, "Timed out waiting for TRIGGER bit\n");
> + return ret;
> + }
> +
> + val = REGB_RD32(VPU_37XX_BUTTRESS_VPU_IP_RESET);
> + val = REG_SET_FLD(VPU_37XX_BUTTRESS_VPU_IP_RESET, TRIGGER, val);
> + REGB_WR32(VPU_37XX_BUTTRESS_VPU_IP_RESET, val);
> +
> + ret = REGB_POLL_FLD(VPU_37XX_BUTTRESS_VPU_IP_RESET, TRIGGER, 0, TIMEOUT_US);
> + if (ret)
> + ivpu_err(vdev, "Timed out waiting for RESET completion\n");
> +
> + return ret;
> +}
> +
> static int ivpu_hw_37xx_reset(struct ivpu_device *vdev)
> {
> int ret = 0;
>
> - if (ivpu_boot_pwr_domain_disable(vdev)) {
> - ivpu_err(vdev, "Failed to disable power domain\n");
> + if (ivpu_hw_37xx_ip_reset(vdev)) {
> + ivpu_err(vdev, "Failed to reset NPU\n");
> ret = -EIO;
> }
>
> @@ -661,6 +676,11 @@ static int ivpu_hw_37xx_power_up(struct ivpu_device *vdev)
> {
> int ret;
>
> + /* PLL requests may fail when powering down, so issue WP 0 here */
> + ret = ivpu_pll_disable(vdev);
> + if (ret)
> + ivpu_warn(vdev, "Failed to disable PLL: %d\n", ret);
> +
> ret = ivpu_hw_37xx_d0i3_disable(vdev);
> if (ret)
> ivpu_warn(vdev, "Failed to disable D0I3: %d\n", ret);
> diff --git a/drivers/accel/ivpu/ivpu_pm.c b/drivers/accel/ivpu/ivpu_pm.c
> index f501f27ebafd..fcc319ee0018 100644
> --- a/drivers/accel/ivpu/ivpu_pm.c
> +++ b/drivers/accel/ivpu/ivpu_pm.c
> @@ -58,11 +58,14 @@ static int ivpu_suspend(struct ivpu_device *vdev)
> {
> int ret;
>
> + /* Save PCI state before powering down as it sometimes gets corrupted if NPU hangs */
> + pci_save_state(to_pci_dev(vdev->drm.dev));
> +
> ret = ivpu_shutdown(vdev);
> - if (ret) {
> + if (ret)
> ivpu_err(vdev, "Failed to shutdown VPU: %d\n", ret);
> - return ret;
> - }
> +
> + pci_set_power_state(to_pci_dev(vdev->drm.dev), PCI_D3hot);
>
> return ret;
> }
> @@ -200,9 +203,6 @@ int ivpu_pm_suspend_cb(struct device *dev)
> ivpu_suspend(vdev);
> ivpu_pm_prepare_warm_boot(vdev);
>
> - pci_save_state(to_pci_dev(dev));
> - pci_set_power_state(to_pci_dev(dev), PCI_D3hot);
> -
> ivpu_dbg(vdev, PM, "Suspend done.\n");
>
> return 0;
More information about the dri-devel
mailing list