提交 c54837e4 编写于 作者: X Xu Qiang 提交者: Yang Yingliang

irqchip/gic-v3-its: Unconditionally save/restore the ITS state on suspend.

mainline inclusion
from mainline-v5.10-rc6
commit 74cde1a5
category: bugfix
bugzilla: NA
CVE: NA

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

On systems without HW-based collections (i.e. anything except GIC-500),
we rely on firmware to perform the ITS save/restore. This doesn't
really work, as although FW can properly save everything, it cannot
fully restore the state of the command queue (the read-side is reset
to the head of the queue). This results in the ITS consuming previously
processed commands, potentially corrupting the state.

Instead, let's always save the ITS state on suspend, disabling it in the
process, and restore the full state on resume. This saves us from broken
FW as long as it doesn't enable the ITS by itself (for which we can't do
anything).

This amounts to simply dropping the ITS_FLAGS_SAVE_SUSPEND_STATE.
Signed-off-by: NXu Qiang <xuqiang36@huawei.com>
[maz: added warning on resume, rewrote commit message]
Signed-off-by: NMarc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20201107104226.14282-1-xuqiang36@huawei.comReviewed-by: NHanjun Guo <guohanjun@huawei.com>
Signed-off-by: NYang Yingliang <yangyingliang@huawei.com>
Signed-off-by: NCheng Jian <cj.chengjian@huawei.com>
上级 db86a8e3
...@@ -54,8 +54,6 @@ ...@@ -54,8 +54,6 @@
#define ITS_FLAGS_CMDQ_NEEDS_FLUSHING (1ULL << 0) #define ITS_FLAGS_CMDQ_NEEDS_FLUSHING (1ULL << 0)
#define ITS_FLAGS_WORKAROUND_CAVIUM_22375 (1ULL << 1) #define ITS_FLAGS_WORKAROUND_CAVIUM_22375 (1ULL << 1)
#define ITS_FLAGS_WORKAROUND_CAVIUM_23144 (1ULL << 2) #define ITS_FLAGS_WORKAROUND_CAVIUM_23144 (1ULL << 2)
#define ITS_FLAGS_SAVE_SUSPEND_STATE (1ULL << 3)
#define ITS_FLAGS_SAVE_HIBERNATE_STATE (1ULL << 4)
#define RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING (1 << 0) #define RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING (1 << 0)
#define RDIST_FLAGS_RD_TABLES_PREALLOCATED (1 << 1) #define RDIST_FLAGS_RD_TABLES_PREALLOCATED (1 << 1)
...@@ -3617,17 +3615,6 @@ static int its_save_disable(void) ...@@ -3617,17 +3615,6 @@ static int its_save_disable(void)
raw_spin_lock(&its_lock); raw_spin_lock(&its_lock);
list_for_each_entry(its, &its_nodes, entry) { list_for_each_entry(its, &its_nodes, entry) {
void __iomem *base; void __iomem *base;
u64 flags;
if (system_in_hibernation())
its->flags |= ITS_FLAGS_SAVE_HIBERNATE_STATE;
flags = its->flags;
flags &= (ITS_FLAGS_SAVE_SUSPEND_STATE |
ITS_FLAGS_SAVE_HIBERNATE_STATE);
if (!flags)
continue;
base = its->base; base = its->base;
its->ctlr_save = readl_relaxed(base + GITS_CTLR); its->ctlr_save = readl_relaxed(base + GITS_CTLR);
...@@ -3647,9 +3634,6 @@ static int its_save_disable(void) ...@@ -3647,9 +3634,6 @@ static int its_save_disable(void)
list_for_each_entry_continue_reverse(its, &its_nodes, entry) { list_for_each_entry_continue_reverse(its, &its_nodes, entry) {
void __iomem *base; void __iomem *base;
if (!(its->flags & ITS_FLAGS_SAVE_SUSPEND_STATE))
continue;
base = its->base; base = its->base;
writel_relaxed(its->ctlr_save, base + GITS_CTLR); writel_relaxed(its->ctlr_save, base + GITS_CTLR);
} }
...@@ -3667,16 +3651,8 @@ static void its_restore_enable(void) ...@@ -3667,16 +3651,8 @@ static void its_restore_enable(void)
raw_spin_lock(&its_lock); raw_spin_lock(&its_lock);
list_for_each_entry(its, &its_nodes, entry) { list_for_each_entry(its, &its_nodes, entry) {
void __iomem *base; void __iomem *base;
u64 flags;
int i; int i;
flags = its->flags;
flags &= (ITS_FLAGS_SAVE_SUSPEND_STATE |
ITS_FLAGS_SAVE_HIBERNATE_STATE);
if (!flags)
continue;
its->flags &= ~ITS_FLAGS_SAVE_HIBERNATE_STATE;
base = its->base; base = its->base;
/* /*
...@@ -3684,7 +3660,10 @@ static void its_restore_enable(void) ...@@ -3684,7 +3660,10 @@ static void its_restore_enable(void)
* don't restore it since writing to CBASER or BASER<n> * don't restore it since writing to CBASER or BASER<n>
* registers is undefined according to the GIC v3 ITS * registers is undefined according to the GIC v3 ITS
* Specification. * Specification.
*
* Firmware resuming with the ITS enabled is terminally broken.
*/ */
WARN_ON(readl_relaxed(base + GITS_CTLR) & GITS_CTLR_ENABLE);
ret = its_force_quiescent(base); ret = its_force_quiescent(base);
if (ret) { if (ret) {
pr_err("ITS@%pa: failed to quiesce on resume: %d\n", pr_err("ITS@%pa: failed to quiesce on resume: %d\n",
...@@ -3950,9 +3929,6 @@ static int __init its_probe_one(struct resource *res, ...@@ -3950,9 +3929,6 @@ static int __init its_probe_one(struct resource *res,
ctlr |= GITS_CTLR_ImDe; ctlr |= GITS_CTLR_ImDe;
writel_relaxed(ctlr, its->base + GITS_CTLR); writel_relaxed(ctlr, its->base + GITS_CTLR);
if (GITS_TYPER_HCC(typer))
its->flags |= ITS_FLAGS_SAVE_SUSPEND_STATE;
err = its_init_domain(handle, its); err = its_init_domain(handle, its);
if (err) if (err)
goto out_free_tables; goto out_free_tables;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册