Commit 74cde1a5 authored by Xu Qiang's avatar Xu Qiang Committed by Marc Zyngier

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

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: default avatarXu Qiang <xuqiang36@huawei.com>
[maz: added warning on resume, rewrote commit message]
Signed-off-by: default avatarMarc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20201107104226.14282-1-xuqiang36@huawei.com
parent d001e41e
...@@ -42,7 +42,6 @@ ...@@ -42,7 +42,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 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)
...@@ -4741,9 +4740,6 @@ static int its_save_disable(void) ...@@ -4741,9 +4740,6 @@ static int its_save_disable(void)
list_for_each_entry(its, &its_nodes, entry) { list_for_each_entry(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;
its->ctlr_save = readl_relaxed(base + GITS_CTLR); its->ctlr_save = readl_relaxed(base + GITS_CTLR);
err = its_force_quiescent(base); err = its_force_quiescent(base);
...@@ -4762,9 +4758,6 @@ static int its_save_disable(void) ...@@ -4762,9 +4758,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);
} }
...@@ -4784,9 +4777,6 @@ static void its_restore_enable(void) ...@@ -4784,9 +4777,6 @@ static void its_restore_enable(void)
void __iomem *base; void __iomem *base;
int i; int i;
if (!(its->flags & ITS_FLAGS_SAVE_SUSPEND_STATE))
continue;
base = its->base; base = its->base;
/* /*
...@@ -4794,7 +4784,10 @@ static void its_restore_enable(void) ...@@ -4794,7 +4784,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",
...@@ -5074,9 +5067,6 @@ static int __init its_probe_one(struct resource *res, ...@@ -5074,9 +5067,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%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment