Re: [PATCH] accel/ivpu: Fix DevTLB errors on suspend/resume

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxxxxxxxx>
> ---
>  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;



[Index of Archives]     [Linux DRI Users]     [Linux Intel Graphics]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux