Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: 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

authored by

Xu Qiang and committed by
Marc Zyngier
74cde1a5 d001e41e

+3 -13
+3 -13
drivers/irqchip/irq-gic-v3-its.c
··· 42 42 #define ITS_FLAGS_CMDQ_NEEDS_FLUSHING (1ULL << 0) 43 43 #define ITS_FLAGS_WORKAROUND_CAVIUM_22375 (1ULL << 1) 44 44 #define ITS_FLAGS_WORKAROUND_CAVIUM_23144 (1ULL << 2) 45 - #define ITS_FLAGS_SAVE_SUSPEND_STATE (1ULL << 3) 46 45 47 46 #define RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING (1 << 0) 48 47 #define RDIST_FLAGS_RD_TABLES_PREALLOCATED (1 << 1) ··· 4740 4741 list_for_each_entry(its, &its_nodes, entry) { 4741 4742 void __iomem *base; 4742 4743 4743 - if (!(its->flags & ITS_FLAGS_SAVE_SUSPEND_STATE)) 4744 - continue; 4745 - 4746 4744 base = its->base; 4747 4745 its->ctlr_save = readl_relaxed(base + GITS_CTLR); 4748 4746 err = its_force_quiescent(base); ··· 4757 4761 if (err) { 4758 4762 list_for_each_entry_continue_reverse(its, &its_nodes, entry) { 4759 4763 void __iomem *base; 4760 - 4761 - if (!(its->flags & ITS_FLAGS_SAVE_SUSPEND_STATE)) 4762 - continue; 4763 4764 4764 4765 base = its->base; 4765 4766 writel_relaxed(its->ctlr_save, base + GITS_CTLR); ··· 4777 4784 void __iomem *base; 4778 4785 int i; 4779 4786 4780 - if (!(its->flags & ITS_FLAGS_SAVE_SUSPEND_STATE)) 4781 - continue; 4782 - 4783 4787 base = its->base; 4784 4788 4785 4789 /* ··· 4784 4794 * don't restore it since writing to CBASER or BASER<n> 4785 4795 * registers is undefined according to the GIC v3 ITS 4786 4796 * Specification. 4797 + * 4798 + * Firmware resuming with the ITS enabled is terminally broken. 4787 4799 */ 4800 + WARN_ON(readl_relaxed(base + GITS_CTLR) & GITS_CTLR_ENABLE); 4788 4801 ret = its_force_quiescent(base); 4789 4802 if (ret) { 4790 4803 pr_err("ITS@%pa: failed to quiesce on resume: %d\n", ··· 5066 5073 if (is_v4(its)) 5067 5074 ctlr |= GITS_CTLR_ImDe; 5068 5075 writel_relaxed(ctlr, its->base + GITS_CTLR); 5069 - 5070 - if (GITS_TYPER_HCC(typer)) 5071 - its->flags |= ITS_FLAGS_SAVE_SUSPEND_STATE; 5072 5076 5073 5077 err = its_init_domain(handle, its); 5074 5078 if (err)