]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - queue-4.20/irqchip-gic-v4-fix-occasional-vlpi-drop.patch
Linux 4.14.106
[thirdparty/kernel/stable-queue.git] / queue-4.20 / irqchip-gic-v4-fix-occasional-vlpi-drop.patch
1 From ce1cb7f4cb920296ef9444a27003005ca94533c4 Mon Sep 17 00:00:00 2001
2 From: Heyi Guo <guoheyi@huawei.com>
3 Date: Thu, 24 Jan 2019 21:37:08 +0800
4 Subject: irqchip/gic-v4: Fix occasional VLPI drop
5
6 [ Upstream commit 6479450f72c1391c03f08affe0d0110f41ae7ca0 ]
7
8 1. In current implementation, every VLPI will temporarily be mapped to
9 the first CPU in system (normally CPU0) and then moved to the real
10 scheduled CPU later.
11
12 2. So there is a time window and a VLPI may be sent to CPU0 instead of
13 the real scheduled vCPU, in a multi-CPU virtual machine.
14
15 3. However, CPU0 may have not been scheduled as a virtual CPU after
16 system boots up, so the value of its GICR_VPROPBASER is unknown at
17 that moment.
18
19 4. If the INTID of VLPI is larger than 2^(GICR_VPROPBASER.IDbits+1),
20 while IDbits is also in unknown state, GIC will behave as if the VLPI
21 is out of range and simply drop it, which results in interrupt missing
22 in Guest.
23
24 As no code will clear GICR_VPROPBASER at runtime, we can safely
25 initialize the IDbits field at boot time for each CPU to get rid of
26 this issue.
27
28 We also clear Valid bit of GICR_VPENDBASER in case any ancient
29 programming gets left in and causes memory corrupting. A new function
30 its_clear_vpend_valid() is added to reuse the code in
31 its_vpe_deschedule().
32
33 Fixes: e643d8034036 ("irqchip/gic-v3-its: Add VPE scheduling")
34 Signed-off-by: Heyi Guo <guoheyi@huawei.com>
35 Signed-off-by: Heyi Guo <heyi.guo@linaro.org>
36 Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
37 Signed-off-by: Sasha Levin <sashal@kernel.org>
38 ---
39 drivers/irqchip/irq-gic-v3-its.c | 66 ++++++++++++++++++++++++--------
40 1 file changed, 49 insertions(+), 17 deletions(-)
41
42 diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
43 index 350f999d205b..f25ec92f23ee 100644
44 --- a/drivers/irqchip/irq-gic-v3-its.c
45 +++ b/drivers/irqchip/irq-gic-v3-its.c
46 @@ -2065,6 +2065,29 @@ static int __init allocate_lpi_tables(void)
47 return 0;
48 }
49
50 +static u64 its_clear_vpend_valid(void __iomem *vlpi_base)
51 +{
52 + u32 count = 1000000; /* 1s! */
53 + bool clean;
54 + u64 val;
55 +
56 + val = gits_read_vpendbaser(vlpi_base + GICR_VPENDBASER);
57 + val &= ~GICR_VPENDBASER_Valid;
58 + gits_write_vpendbaser(val, vlpi_base + GICR_VPENDBASER);
59 +
60 + do {
61 + val = gits_read_vpendbaser(vlpi_base + GICR_VPENDBASER);
62 + clean = !(val & GICR_VPENDBASER_Dirty);
63 + if (!clean) {
64 + count--;
65 + cpu_relax();
66 + udelay(1);
67 + }
68 + } while (!clean && count);
69 +
70 + return val;
71 +}
72 +
73 static void its_cpu_init_lpis(void)
74 {
75 void __iomem *rbase = gic_data_rdist_rd_base();
76 @@ -2150,6 +2173,30 @@ static void its_cpu_init_lpis(void)
77 val |= GICR_CTLR_ENABLE_LPIS;
78 writel_relaxed(val, rbase + GICR_CTLR);
79
80 + if (gic_rdists->has_vlpis) {
81 + void __iomem *vlpi_base = gic_data_rdist_vlpi_base();
82 +
83 + /*
84 + * It's possible for CPU to receive VLPIs before it is
85 + * sheduled as a vPE, especially for the first CPU, and the
86 + * VLPI with INTID larger than 2^(IDbits+1) will be considered
87 + * as out of range and dropped by GIC.
88 + * So we initialize IDbits to known value to avoid VLPI drop.
89 + */
90 + val = (LPI_NRBITS - 1) & GICR_VPROPBASER_IDBITS_MASK;
91 + pr_debug("GICv4: CPU%d: Init IDbits to 0x%llx for GICR_VPROPBASER\n",
92 + smp_processor_id(), val);
93 + gits_write_vpropbaser(val, vlpi_base + GICR_VPROPBASER);
94 +
95 + /*
96 + * Also clear Valid bit of GICR_VPENDBASER, in case some
97 + * ancient programming gets left in and has possibility of
98 + * corrupting memory.
99 + */
100 + val = its_clear_vpend_valid(vlpi_base);
101 + WARN_ON(val & GICR_VPENDBASER_Dirty);
102 + }
103 +
104 /* Make sure the GIC has seen the above */
105 dsb(sy);
106 out:
107 @@ -2776,26 +2823,11 @@ static void its_vpe_schedule(struct its_vpe *vpe)
108 static void its_vpe_deschedule(struct its_vpe *vpe)
109 {
110 void __iomem *vlpi_base = gic_data_rdist_vlpi_base();
111 - u32 count = 1000000; /* 1s! */
112 - bool clean;
113 u64 val;
114
115 - /* We're being scheduled out */
116 - val = gits_read_vpendbaser(vlpi_base + GICR_VPENDBASER);
117 - val &= ~GICR_VPENDBASER_Valid;
118 - gits_write_vpendbaser(val, vlpi_base + GICR_VPENDBASER);
119 -
120 - do {
121 - val = gits_read_vpendbaser(vlpi_base + GICR_VPENDBASER);
122 - clean = !(val & GICR_VPENDBASER_Dirty);
123 - if (!clean) {
124 - count--;
125 - cpu_relax();
126 - udelay(1);
127 - }
128 - } while (!clean && count);
129 + val = its_clear_vpend_valid(vlpi_base);
130
131 - if (unlikely(!clean && !count)) {
132 + if (unlikely(val & GICR_VPENDBASER_Dirty)) {
133 pr_err_ratelimited("ITS virtual pending table not cleaning\n");
134 vpe->idai = false;
135 vpe->pending_last = true;
136 --
137 2.19.1
138