Skip to content

Commit 926846a

Browse files
author
Marc Zyngier
committed
irqchip/gic-v4.1: Properly lock VPEs when doing a directLPI invalidation
We normally rely on the irq_to_cpuid_[un]lock() primitives to make sure nothing will change col->idx while performing a LPI invalidation. However, these primitives do not cover VPE doorbells, and we have some open-coded locking for that. Unfortunately, this locking is pretty bogus. Instead, extend the above primitives to cover VPE doorbells and convert the whole thing to it. Fixes: f3a0592 ("irqchip/gic-v4.1: Ensure mutual exclusion between vPE affinity change and RD access") Reported-by: Kunkun Jiang <jiangkunkun@huawei.com> Signed-off-by: Marc Zyngier <maz@kernel.org> Cc: Zenghui Yu <yuzenghui@huawei.com> Cc: wanghaibin.wang@huawei.com Tested-by: Kunkun Jiang <jiangkunkun@huawei.com> Reviewed-by: Zenghui Yu <yuzenghui@huawei.com> Link: https://lore.kernel.org/r/20230617073242.3199746-1-maz@kernel.org
1 parent 55ad248 commit 926846a

File tree

1 file changed

+46
-29
lines changed

1 file changed

+46
-29
lines changed

drivers/irqchip/irq-gic-v3-its.c

Lines changed: 46 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -273,13 +273,23 @@ static void vpe_to_cpuid_unlock(struct its_vpe *vpe, unsigned long flags)
273273
raw_spin_unlock_irqrestore(&vpe->vpe_lock, flags);
274274
}
275275

276+
static struct irq_chip its_vpe_irq_chip;
277+
276278
static int irq_to_cpuid_lock(struct irq_data *d, unsigned long *flags)
277279
{
278-
struct its_vlpi_map *map = get_vlpi_map(d);
280+
struct its_vpe *vpe = NULL;
279281
int cpu;
280282

281-
if (map) {
282-
cpu = vpe_to_cpuid_lock(map->vpe, flags);
283+
if (d->chip == &its_vpe_irq_chip) {
284+
vpe = irq_data_get_irq_chip_data(d);
285+
} else {
286+
struct its_vlpi_map *map = get_vlpi_map(d);
287+
if (map)
288+
vpe = map->vpe;
289+
}
290+
291+
if (vpe) {
292+
cpu = vpe_to_cpuid_lock(vpe, flags);
283293
} else {
284294
/* Physical LPIs are already locked via the irq_desc lock */
285295
struct its_device *its_dev = irq_data_get_irq_chip_data(d);
@@ -293,10 +303,18 @@ static int irq_to_cpuid_lock(struct irq_data *d, unsigned long *flags)
293303

294304
static void irq_to_cpuid_unlock(struct irq_data *d, unsigned long flags)
295305
{
296-
struct its_vlpi_map *map = get_vlpi_map(d);
306+
struct its_vpe *vpe = NULL;
307+
308+
if (d->chip == &its_vpe_irq_chip) {
309+
vpe = irq_data_get_irq_chip_data(d);
310+
} else {
311+
struct its_vlpi_map *map = get_vlpi_map(d);
312+
if (map)
313+
vpe = map->vpe;
314+
}
297315

298-
if (map)
299-
vpe_to_cpuid_unlock(map->vpe, flags);
316+
if (vpe)
317+
vpe_to_cpuid_unlock(vpe, flags);
300318
}
301319

302320
static struct its_collection *valid_col(struct its_collection *col)
@@ -1433,14 +1451,29 @@ static void wait_for_syncr(void __iomem *rdbase)
14331451
cpu_relax();
14341452
}
14351453

1436-
static void direct_lpi_inv(struct irq_data *d)
1454+
static void __direct_lpi_inv(struct irq_data *d, u64 val)
14371455
{
1438-
struct its_vlpi_map *map = get_vlpi_map(d);
14391456
void __iomem *rdbase;
14401457
unsigned long flags;
1441-
u64 val;
14421458
int cpu;
14431459

1460+
/* Target the redistributor this LPI is currently routed to */
1461+
cpu = irq_to_cpuid_lock(d, &flags);
1462+
raw_spin_lock(&gic_data_rdist_cpu(cpu)->rd_lock);
1463+
1464+
rdbase = per_cpu_ptr(gic_rdists->rdist, cpu)->rd_base;
1465+
gic_write_lpir(val, rdbase + GICR_INVLPIR);
1466+
wait_for_syncr(rdbase);
1467+
1468+
raw_spin_unlock(&gic_data_rdist_cpu(cpu)->rd_lock);
1469+
irq_to_cpuid_unlock(d, flags);
1470+
}
1471+
1472+
static void direct_lpi_inv(struct irq_data *d)
1473+
{
1474+
struct its_vlpi_map *map = get_vlpi_map(d);
1475+
u64 val;
1476+
14441477
if (map) {
14451478
struct its_device *its_dev = irq_data_get_irq_chip_data(d);
14461479

@@ -1453,15 +1486,7 @@ static void direct_lpi_inv(struct irq_data *d)
14531486
val = d->hwirq;
14541487
}
14551488

1456-
/* Target the redistributor this LPI is currently routed to */
1457-
cpu = irq_to_cpuid_lock(d, &flags);
1458-
raw_spin_lock(&gic_data_rdist_cpu(cpu)->rd_lock);
1459-
rdbase = per_cpu_ptr(gic_rdists->rdist, cpu)->rd_base;
1460-
gic_write_lpir(val, rdbase + GICR_INVLPIR);
1461-
1462-
wait_for_syncr(rdbase);
1463-
raw_spin_unlock(&gic_data_rdist_cpu(cpu)->rd_lock);
1464-
irq_to_cpuid_unlock(d, flags);
1489+
__direct_lpi_inv(d, val);
14651490
}
14661491

14671492
static void lpi_update_config(struct irq_data *d, u8 clr, u8 set)
@@ -3953,18 +3978,10 @@ static void its_vpe_send_inv(struct irq_data *d)
39533978
{
39543979
struct its_vpe *vpe = irq_data_get_irq_chip_data(d);
39553980

3956-
if (gic_rdists->has_direct_lpi) {
3957-
void __iomem *rdbase;
3958-
3959-
/* Target the redistributor this VPE is currently known on */
3960-
raw_spin_lock(&gic_data_rdist_cpu(vpe->col_idx)->rd_lock);
3961-
rdbase = per_cpu_ptr(gic_rdists->rdist, vpe->col_idx)->rd_base;
3962-
gic_write_lpir(d->parent_data->hwirq, rdbase + GICR_INVLPIR);
3963-
wait_for_syncr(rdbase);
3964-
raw_spin_unlock(&gic_data_rdist_cpu(vpe->col_idx)->rd_lock);
3965-
} else {
3981+
if (gic_rdists->has_direct_lpi)
3982+
__direct_lpi_inv(d, d->parent_data->hwirq);
3983+
else
39663984
its_vpe_send_cmd(vpe, its_send_inv);
3967-
}
39683985
}
39693986

39703987
static void its_vpe_mask_irq(struct irq_data *d)

0 commit comments

Comments
 (0)