Skip to content

Commit f0eb154

Browse files
Marc ZyngierKAGA-KOKO
authored andcommitted
irqchip/gic-v4: Substitute vmovp_lock for a per-VM lock
vmovp_lock is abused in a number of cases to serialise updates to vlpi_count[] and deal with map/unmap of a VM to ITSs. Instead, provide a per-VM lock and revisit the use of vlpi_count[] so that it is always wrapped in this per-VM vmapp_lock. This reduces the potential contention on a concurrent VMOVP command, and paves the way for subsequent VPE locking that holding vmovp_lock actively prevents due to the lock ordering. Signed-off-by: Marc Zyngier <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Tested-by: Nianyao Tang <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 7d2c204 commit f0eb154

File tree

2 files changed

+20
-15
lines changed

2 files changed

+20
-15
lines changed

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

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1317,7 +1317,6 @@ static void its_send_vmovp(struct its_vpe *vpe)
13171317
{
13181318
struct its_cmd_desc desc = {};
13191319
struct its_node *its;
1320-
unsigned long flags;
13211320
int col_id = vpe->col_idx;
13221321

13231322
desc.its_vmovp_cmd.vpe = vpe;
@@ -1329,6 +1328,12 @@ static void its_send_vmovp(struct its_vpe *vpe)
13291328
return;
13301329
}
13311330

1331+
/*
1332+
* Protect against concurrent updates of the mapping state on
1333+
* individual VMs.
1334+
*/
1335+
guard(raw_spinlock_irqsave)(&vpe->its_vm->vmapp_lock);
1336+
13321337
/*
13331338
* Yet another marvel of the architecture. If using the
13341339
* its_list "feature", we need to make sure that all ITSs
@@ -1337,8 +1342,7 @@ static void its_send_vmovp(struct its_vpe *vpe)
13371342
*
13381343
* Wall <-- Head.
13391344
*/
1340-
raw_spin_lock_irqsave(&vmovp_lock, flags);
1341-
1345+
guard(raw_spinlock)(&vmovp_lock);
13421346
desc.its_vmovp_cmd.seq_num = vmovp_seq_num++;
13431347
desc.its_vmovp_cmd.its_list = get_its_list(vpe->its_vm);
13441348

@@ -1353,8 +1357,6 @@ static void its_send_vmovp(struct its_vpe *vpe)
13531357
desc.its_vmovp_cmd.col = &its->collections[col_id];
13541358
its_send_single_vcommand(its, its_build_vmovp_cmd, &desc);
13551359
}
1356-
1357-
raw_spin_unlock_irqrestore(&vmovp_lock, flags);
13581360
}
13591361

13601362
static void its_send_vinvall(struct its_node *its, struct its_vpe *vpe)
@@ -1791,12 +1793,10 @@ static bool gic_requires_eager_mapping(void)
17911793

17921794
static void its_map_vm(struct its_node *its, struct its_vm *vm)
17931795
{
1794-
unsigned long flags;
1795-
17961796
if (gic_requires_eager_mapping())
17971797
return;
17981798

1799-
raw_spin_lock_irqsave(&vmovp_lock, flags);
1799+
guard(raw_spinlock_irqsave)(&vm->vmapp_lock);
18001800

18011801
/*
18021802
* If the VM wasn't mapped yet, iterate over the vpes and get
@@ -1814,28 +1814,22 @@ static void its_map_vm(struct its_node *its, struct its_vm *vm)
18141814
its_send_vinvall(its, vpe);
18151815
}
18161816
}
1817-
1818-
raw_spin_unlock_irqrestore(&vmovp_lock, flags);
18191817
}
18201818

18211819
static void its_unmap_vm(struct its_node *its, struct its_vm *vm)
18221820
{
1823-
unsigned long flags;
1824-
18251821
/* Not using the ITS list? Everything is always mapped. */
18261822
if (gic_requires_eager_mapping())
18271823
return;
18281824

1829-
raw_spin_lock_irqsave(&vmovp_lock, flags);
1825+
guard(raw_spinlock_irqsave)(&vm->vmapp_lock);
18301826

18311827
if (!--vm->vlpi_count[its->list_nr]) {
18321828
int i;
18331829

18341830
for (i = 0; i < vm->nr_vpes; i++)
18351831
its_send_vmapp(its, vm->vpes[i], false);
18361832
}
1837-
1838-
raw_spin_unlock_irqrestore(&vmovp_lock, flags);
18391833
}
18401834

18411835
static int its_vlpi_map(struct irq_data *d, struct its_cmd_info *info)
@@ -3942,6 +3936,8 @@ static void its_vpe_invall(struct its_vpe *vpe)
39423936
{
39433937
struct its_node *its;
39443938

3939+
guard(raw_spinlock_irqsave)(&vpe->its_vm->vmapp_lock);
3940+
39453941
list_for_each_entry(its, &its_nodes, entry) {
39463942
if (!is_v4(its))
39473943
continue;
@@ -4547,6 +4543,7 @@ static int its_vpe_irq_domain_alloc(struct irq_domain *domain, unsigned int virq
45474543
vm->db_lpi_base = base;
45484544
vm->nr_db_lpis = nr_ids;
45494545
vm->vprop_page = vprop_page;
4546+
raw_spin_lock_init(&vm->vmapp_lock);
45504547

45514548
if (gic_rdists->has_rvpeid)
45524549
irqchip = &its_vpe_4_1_irq_chip;

include/linux/irqchip/arm-gic-v4.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,14 @@ struct its_vm {
2525
irq_hw_number_t db_lpi_base;
2626
unsigned long *db_bitmap;
2727
int nr_db_lpis;
28+
/*
29+
* Ensures mutual exclusion between updates to vlpi_count[]
30+
* and map/unmap when using the ITSList mechanism.
31+
*
32+
* The lock order for any sequence involving the ITSList is
33+
* vmapp_lock -> vpe_lock ->vmovp_lock.
34+
*/
35+
raw_spinlock_t vmapp_lock;
2836
u32 vlpi_count[GICv4_ITS_LIST_MAX];
2937
};
3038

0 commit comments

Comments
 (0)