Commit f7393289 authored by Brian Norris's avatar Brian Norris Committed by Zheng Zucheng
Browse files

spi: rockchip: Resolve unbalanced runtime PM / system PM handling

stable inclusion
from stable-v6.6.51
commit d034bff62faea1a2219e0d2f3d17263265f24087
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/IAU9NV
CVE: CVE-2024-46846

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=d034bff62faea1a2219e0d2f3d17263265f24087



--------------------------------

commit be721b451affbecc4ba4eaac3b71cdbdcade1b1b upstream.

Commit e882575e ("spi: rockchip: Suspend and resume the bus during
NOIRQ_SYSTEM_SLEEP_PM ops") stopped respecting runtime PM status and
simply disabled clocks unconditionally when suspending the system. This
causes problems when the device is already runtime suspended when we go
to sleep -- in which case we double-disable clocks and produce a
WARNing.

Switch back to pm_runtime_force_{suspend,resume}(), because that still
seems like the right thing to do, and the aforementioned commit makes no
explanation why it stopped using it.

Also, refactor some of the resume() error handling, because it's not
actually a good idea to re-disable clocks on failure.

Fixes: e882575e ("spi: rockchip: Suspend and resume the bus during NOIRQ_SYSTEM_SLEEP_PM ops")
Cc: stable@vger.kernel.org
Reported-by: default avatarOndřej Jirman <megi@xff.cz>
Closes: https://lore.kernel.org/lkml/20220621154218.sau54jeij4bunf56@core/


Signed-off-by: default avatarBrian Norris <briannorris@chromium.org>
Link: https://patch.msgid.link/20240827171126.1115748-1-briannorris@chromium.org


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: default avatarZheng Zucheng <zhengzucheng@huawei.com>
parent c594039d
Loading
Loading
Loading
Loading
+7 −16
Original line number Diff line number Diff line
@@ -974,14 +974,16 @@ static int rockchip_spi_suspend(struct device *dev)
{
	int ret;
	struct spi_controller *ctlr = dev_get_drvdata(dev);
	struct rockchip_spi *rs = spi_controller_get_devdata(ctlr);

	ret = spi_controller_suspend(ctlr);
	if (ret < 0)
		return ret;

	clk_disable_unprepare(rs->spiclk);
	clk_disable_unprepare(rs->apb_pclk);
	ret = pm_runtime_force_suspend(dev);
	if (ret < 0) {
		spi_controller_resume(ctlr);
		return ret;
	}

	pinctrl_pm_select_sleep_state(dev);

@@ -992,25 +994,14 @@ static int rockchip_spi_resume(struct device *dev)
{
	int ret;
	struct spi_controller *ctlr = dev_get_drvdata(dev);
	struct rockchip_spi *rs = spi_controller_get_devdata(ctlr);

	pinctrl_pm_select_default_state(dev);

	ret = clk_prepare_enable(rs->apb_pclk);
	ret = pm_runtime_force_resume(dev);
	if (ret < 0)
		return ret;

	ret = clk_prepare_enable(rs->spiclk);
	if (ret < 0)
		clk_disable_unprepare(rs->apb_pclk);

	ret = spi_controller_resume(ctlr);
	if (ret < 0) {
		clk_disable_unprepare(rs->spiclk);
		clk_disable_unprepare(rs->apb_pclk);
	}

	return 0;
	return spi_controller_resume(ctlr);
}
#endif /* CONFIG_PM_SLEEP */