Skip to content

Commit

Permalink
irqchip/gic-v3-its: Unconditionally save/restore the ITS state on sus…
Browse files Browse the repository at this point in the history
…pend

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: Xu Qiang <xuqiang36@huawei.com>
[maz: added warning on resume, rewrote commit message]
Signed-off-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20201107104226.14282-1-xuqiang36@huawei.com
  • Loading branch information
Xu Qiang authored and Marc Zyngier committed Nov 22, 2020
1 parent d001e41 commit 74cde1a
Showing 1 changed file with 3 additions and 13 deletions.
16 changes: 3 additions & 13 deletions drivers/irqchip/irq-gic-v3-its.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@
#define ITS_FLAGS_CMDQ_NEEDS_FLUSHING (1ULL << 0)
#define ITS_FLAGS_WORKAROUND_CAVIUM_22375 (1ULL << 1)
#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_RD_TABLES_PREALLOCATED (1 << 1)
Expand Down Expand Up @@ -4741,9 +4740,6 @@ static int its_save_disable(void)
list_for_each_entry(its, &its_nodes, entry) {
void __iomem *base;

if (!(its->flags & ITS_FLAGS_SAVE_SUSPEND_STATE))
continue;

base = its->base;
its->ctlr_save = readl_relaxed(base + GITS_CTLR);
err = its_force_quiescent(base);
Expand All @@ -4762,9 +4758,6 @@ static int its_save_disable(void)
list_for_each_entry_continue_reverse(its, &its_nodes, entry) {
void __iomem *base;

if (!(its->flags & ITS_FLAGS_SAVE_SUSPEND_STATE))
continue;

base = its->base;
writel_relaxed(its->ctlr_save, base + GITS_CTLR);
}
Expand All @@ -4784,17 +4777,17 @@ static void its_restore_enable(void)
void __iomem *base;
int i;

if (!(its->flags & ITS_FLAGS_SAVE_SUSPEND_STATE))
continue;

base = its->base;

/*
* Make sure that the ITS is disabled. If it fails to quiesce,
* don't restore it since writing to CBASER or BASER<n>
* registers is undefined according to the GIC v3 ITS
* 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);
if (ret) {
pr_err("ITS@%pa: failed to quiesce on resume: %d\n",
Expand Down Expand Up @@ -5074,9 +5067,6 @@ static int __init its_probe_one(struct resource *res,
ctlr |= GITS_CTLR_ImDe;
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);
if (err)
goto out_free_tables;
Expand Down

0 comments on commit 74cde1a

Please sign in to comment.