Commit 7ed51e3a authored by Pratap Nirujogi's avatar Pratap Nirujogi Committed by Alex Deucher
Browse files

drm/amd/amdgpu: Fix SMU warning during isp suspend-resume



ISP mfd child devices are using genpd and the system suspend-resume
operations between genpd and amdgpu parent device which uses only
runtime suspend-resume are not in sync.

Linux power manager during suspend-resume resuming the genpd devices
earlier than the amdgpu parent device. This is resulting in the below
warning as SMU is in suspended state when genpd attempts to resume ISP.

WARNING: CPU: 13 PID: 5435 at drivers/gpu/drm/amd/amdgpu/../pm/swsmu/amdgpu_smu.c:398 smu_dpm_set_power_gate+0x36f/0x380 [amdgpu]

To fix this warning isp suspend-resume is handled as part of amdgpu
parent device suspend-resume instead of genpd sequence. Each ISP MFD
child device is marked as dev_pm_syscore_device to skip genpd
suspend-resume and use pm_runtime_force api's to suspend-resume
the devices when callbacks from amdgpu are received.

Co-developed-by: default avatarGjorgji Rosikopulos <grosikop@amd.com>
Signed-off-by: default avatarGjorgji Rosikopulos <grosikop@amd.com>
Signed-off-by: default avatarBin Du <bin.du@amd.com>
Signed-off-by: default avatarPratap Nirujogi <pratap.nirujogi@amd.com>
Reviewed-by: default avatarMario Limonciello (AMD) <superm1@kernel.org>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
(cherry picked from commit 0288a345)
parent 531b4326
Loading
Loading
Loading
Loading
+24 −0
Original line number Diff line number Diff line
@@ -318,12 +318,36 @@ void isp_kernel_buffer_free(void **buf_obj, u64 *gpu_addr, void **cpu_addr)
}
EXPORT_SYMBOL(isp_kernel_buffer_free);

static int isp_resume(struct amdgpu_ip_block *ip_block)
{
	struct amdgpu_device *adev = ip_block->adev;
	struct amdgpu_isp *isp = &adev->isp;

	if (isp->funcs->hw_resume)
		return isp->funcs->hw_resume(isp);

	return -ENODEV;
}

static int isp_suspend(struct amdgpu_ip_block *ip_block)
{
	struct amdgpu_device *adev = ip_block->adev;
	struct amdgpu_isp *isp = &adev->isp;

	if (isp->funcs->hw_suspend)
		return isp->funcs->hw_suspend(isp);

	return -ENODEV;
}

static const struct amd_ip_funcs isp_ip_funcs = {
	.name = "isp_ip",
	.early_init = isp_early_init,
	.hw_init = isp_hw_init,
	.hw_fini = isp_hw_fini,
	.is_idle = isp_is_idle,
	.suspend = isp_suspend,
	.resume = isp_resume,
	.set_clockgating_state = isp_set_clockgating_state,
	.set_powergating_state = isp_set_powergating_state,
};
+2 −0
Original line number Diff line number Diff line
@@ -38,6 +38,8 @@ struct amdgpu_isp;
struct isp_funcs {
	int (*hw_init)(struct amdgpu_isp *isp);
	int (*hw_fini)(struct amdgpu_isp *isp);
	int (*hw_suspend)(struct amdgpu_isp *isp);
	int (*hw_resume)(struct amdgpu_isp *isp);
};

struct amdgpu_isp {
+41 −0
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@
 */

#include <linux/gpio/machine.h>
#include <linux/pm_runtime.h>
#include "amdgpu.h"
#include "isp_v4_1_1.h"

@@ -145,6 +146,9 @@ static int isp_genpd_add_device(struct device *dev, void *data)
		return -ENODEV;
	}

	/* The devices will be managed by the pm ops from the parent */
	dev_pm_syscore_device(dev, true);

exit:
	/* Continue to add */
	return 0;
@@ -177,12 +181,47 @@ static int isp_genpd_remove_device(struct device *dev, void *data)
		drm_err(&adev->ddev, "Failed to remove dev from genpd %d\n", ret);
		return -ENODEV;
	}
	dev_pm_syscore_device(dev, false);

exit:
	/* Continue to remove */
	return 0;
}

static int isp_suspend_device(struct device *dev, void *data)
{
	return pm_runtime_force_suspend(dev);
}

static int isp_resume_device(struct device *dev, void *data)
{
	return pm_runtime_force_resume(dev);
}

static int isp_v4_1_1_hw_suspend(struct amdgpu_isp *isp)
{
	int r;

	r = device_for_each_child(isp->parent, NULL,
				  isp_suspend_device);
	if (r)
		dev_err(isp->parent, "failed to suspend hw devices (%d)\n", r);

	return r;
}

static int isp_v4_1_1_hw_resume(struct amdgpu_isp *isp)
{
	int r;

	r = device_for_each_child(isp->parent, NULL,
				  isp_resume_device);
	if (r)
		dev_err(isp->parent, "failed to resume hw device (%d)\n", r);

	return r;
}

static int isp_v4_1_1_hw_init(struct amdgpu_isp *isp)
{
	const struct software_node *amd_camera_node, *isp4_node;
@@ -369,6 +408,8 @@ static int isp_v4_1_1_hw_fini(struct amdgpu_isp *isp)
static const struct isp_funcs isp_v4_1_1_funcs = {
	.hw_init = isp_v4_1_1_hw_init,
	.hw_fini = isp_v4_1_1_hw_fini,
	.hw_suspend = isp_v4_1_1_hw_suspend,
	.hw_resume = isp_v4_1_1_hw_resume,
};

void isp_v4_1_1_set_isp_funcs(struct amdgpu_isp *isp)