Skip to content

Commit 006df0f

Browse files
Christoffer Dallchazy
authored andcommitted
KVM: arm/arm64: Support calling vgic_update_irq_pending from irq context
We are about to optimize our timer handling logic which involves injecting irqs to the vgic directly from the irq handler. Unfortunately, the injection path can take any AP list lock and irq lock and we must therefore make sure to use spin_lock_irqsave where ever interrupts are enabled and we are taking any of those locks, to avoid deadlocking between process context and the ISR. This changes a lot of the VGIC code, but the good news are that the changes are mostly mechanical. Acked-by: Marc Zyngier <marc,[email protected]> Signed-off-by: Christoffer Dall <[email protected]>
1 parent f39d16c commit 006df0f

File tree

8 files changed

+107
-72
lines changed

8 files changed

+107
-72
lines changed

virt/kvm/arm/vgic/vgic-its.c

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -278,22 +278,23 @@ static int update_lpi_config(struct kvm *kvm, struct vgic_irq *irq,
278278
u64 propbase = GICR_PROPBASER_ADDRESS(kvm->arch.vgic.propbaser);
279279
u8 prop;
280280
int ret;
281+
unsigned long flags;
281282

282283
ret = kvm_read_guest(kvm, propbase + irq->intid - GIC_LPI_OFFSET,
283284
&prop, 1);
284285

285286
if (ret)
286287
return ret;
287288

288-
spin_lock(&irq->irq_lock);
289+
spin_lock_irqsave(&irq->irq_lock, flags);
289290

290291
if (!filter_vcpu || filter_vcpu == irq->target_vcpu) {
291292
irq->priority = LPI_PROP_PRIORITY(prop);
292293
irq->enabled = LPI_PROP_ENABLE_BIT(prop);
293294

294-
vgic_queue_irq_unlock(kvm, irq);
295+
vgic_queue_irq_unlock(kvm, irq, flags);
295296
} else {
296-
spin_unlock(&irq->irq_lock);
297+
spin_unlock_irqrestore(&irq->irq_lock, flags);
297298
}
298299

299300
return 0;
@@ -393,6 +394,7 @@ static int its_sync_lpi_pending_table(struct kvm_vcpu *vcpu)
393394
int ret = 0;
394395
u32 *intids;
395396
int nr_irqs, i;
397+
unsigned long flags;
396398

397399
nr_irqs = vgic_copy_lpi_list(vcpu, &intids);
398400
if (nr_irqs < 0)
@@ -420,9 +422,9 @@ static int its_sync_lpi_pending_table(struct kvm_vcpu *vcpu)
420422
}
421423

422424
irq = vgic_get_irq(vcpu->kvm, NULL, intids[i]);
423-
spin_lock(&irq->irq_lock);
425+
spin_lock_irqsave(&irq->irq_lock, flags);
424426
irq->pending_latch = pendmask & (1U << bit_nr);
425-
vgic_queue_irq_unlock(vcpu->kvm, irq);
427+
vgic_queue_irq_unlock(vcpu->kvm, irq, flags);
426428
vgic_put_irq(vcpu->kvm, irq);
427429
}
428430

@@ -515,6 +517,7 @@ static int vgic_its_trigger_msi(struct kvm *kvm, struct vgic_its *its,
515517
{
516518
struct kvm_vcpu *vcpu;
517519
struct its_ite *ite;
520+
unsigned long flags;
518521

519522
if (!its->enabled)
520523
return -EBUSY;
@@ -530,9 +533,9 @@ static int vgic_its_trigger_msi(struct kvm *kvm, struct vgic_its *its,
530533
if (!vcpu->arch.vgic_cpu.lpis_enabled)
531534
return -EBUSY;
532535

533-
spin_lock(&ite->irq->irq_lock);
536+
spin_lock_irqsave(&ite->irq->irq_lock, flags);
534537
ite->irq->pending_latch = true;
535-
vgic_queue_irq_unlock(kvm, ite->irq);
538+
vgic_queue_irq_unlock(kvm, ite->irq, flags);
536539

537540
return 0;
538541
}

virt/kvm/arm/vgic/vgic-mmio-v2.c

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ static void vgic_mmio_write_sgir(struct kvm_vcpu *source_vcpu,
7474
int mode = (val >> 24) & 0x03;
7575
int c;
7676
struct kvm_vcpu *vcpu;
77+
unsigned long flags;
7778

7879
switch (mode) {
7980
case 0x0: /* as specified by targets */
@@ -97,11 +98,11 @@ static void vgic_mmio_write_sgir(struct kvm_vcpu *source_vcpu,
9798

9899
irq = vgic_get_irq(source_vcpu->kvm, vcpu, intid);
99100

100-
spin_lock(&irq->irq_lock);
101+
spin_lock_irqsave(&irq->irq_lock, flags);
101102
irq->pending_latch = true;
102103
irq->source |= 1U << source_vcpu->vcpu_id;
103104

104-
vgic_queue_irq_unlock(source_vcpu->kvm, irq);
105+
vgic_queue_irq_unlock(source_vcpu->kvm, irq, flags);
105106
vgic_put_irq(source_vcpu->kvm, irq);
106107
}
107108
}
@@ -131,6 +132,7 @@ static void vgic_mmio_write_target(struct kvm_vcpu *vcpu,
131132
u32 intid = VGIC_ADDR_TO_INTID(addr, 8);
132133
u8 cpu_mask = GENMASK(atomic_read(&vcpu->kvm->online_vcpus) - 1, 0);
133134
int i;
135+
unsigned long flags;
134136

135137
/* GICD_ITARGETSR[0-7] are read-only */
136138
if (intid < VGIC_NR_PRIVATE_IRQS)
@@ -140,13 +142,13 @@ static void vgic_mmio_write_target(struct kvm_vcpu *vcpu,
140142
struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, NULL, intid + i);
141143
int target;
142144

143-
spin_lock(&irq->irq_lock);
145+
spin_lock_irqsave(&irq->irq_lock, flags);
144146

145147
irq->targets = (val >> (i * 8)) & cpu_mask;
146148
target = irq->targets ? __ffs(irq->targets) : 0;
147149
irq->target_vcpu = kvm_get_vcpu(vcpu->kvm, target);
148150

149-
spin_unlock(&irq->irq_lock);
151+
spin_unlock_irqrestore(&irq->irq_lock, flags);
150152
vgic_put_irq(vcpu->kvm, irq);
151153
}
152154
}
@@ -174,17 +176,18 @@ static void vgic_mmio_write_sgipendc(struct kvm_vcpu *vcpu,
174176
{
175177
u32 intid = addr & 0x0f;
176178
int i;
179+
unsigned long flags;
177180

178181
for (i = 0; i < len; i++) {
179182
struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
180183

181-
spin_lock(&irq->irq_lock);
184+
spin_lock_irqsave(&irq->irq_lock, flags);
182185

183186
irq->source &= ~((val >> (i * 8)) & 0xff);
184187
if (!irq->source)
185188
irq->pending_latch = false;
186189

187-
spin_unlock(&irq->irq_lock);
190+
spin_unlock_irqrestore(&irq->irq_lock, flags);
188191
vgic_put_irq(vcpu->kvm, irq);
189192
}
190193
}
@@ -195,19 +198,20 @@ static void vgic_mmio_write_sgipends(struct kvm_vcpu *vcpu,
195198
{
196199
u32 intid = addr & 0x0f;
197200
int i;
201+
unsigned long flags;
198202

199203
for (i = 0; i < len; i++) {
200204
struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
201205

202-
spin_lock(&irq->irq_lock);
206+
spin_lock_irqsave(&irq->irq_lock, flags);
203207

204208
irq->source |= (val >> (i * 8)) & 0xff;
205209

206210
if (irq->source) {
207211
irq->pending_latch = true;
208-
vgic_queue_irq_unlock(vcpu->kvm, irq);
212+
vgic_queue_irq_unlock(vcpu->kvm, irq, flags);
209213
} else {
210-
spin_unlock(&irq->irq_lock);
214+
spin_unlock_irqrestore(&irq->irq_lock, flags);
211215
}
212216
vgic_put_irq(vcpu->kvm, irq);
213217
}

virt/kvm/arm/vgic/vgic-mmio-v3.c

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ static void vgic_mmio_write_irouter(struct kvm_vcpu *vcpu,
129129
{
130130
int intid = VGIC_ADDR_TO_INTID(addr, 64);
131131
struct vgic_irq *irq;
132+
unsigned long flags;
132133

133134
/* The upper word is WI for us since we don't implement Aff3. */
134135
if (addr & 4)
@@ -139,13 +140,13 @@ static void vgic_mmio_write_irouter(struct kvm_vcpu *vcpu,
139140
if (!irq)
140141
return;
141142

142-
spin_lock(&irq->irq_lock);
143+
spin_lock_irqsave(&irq->irq_lock, flags);
143144

144145
/* We only care about and preserve Aff0, Aff1 and Aff2. */
145146
irq->mpidr = val & GENMASK(23, 0);
146147
irq->target_vcpu = kvm_mpidr_to_vcpu(vcpu->kvm, irq->mpidr);
147148

148-
spin_unlock(&irq->irq_lock);
149+
spin_unlock_irqrestore(&irq->irq_lock, flags);
149150
vgic_put_irq(vcpu->kvm, irq);
150151
}
151152

@@ -241,22 +242,23 @@ static void vgic_v3_uaccess_write_pending(struct kvm_vcpu *vcpu,
241242
{
242243
u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
243244
int i;
245+
unsigned long flags;
244246

245247
for (i = 0; i < len * 8; i++) {
246248
struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
247249

248-
spin_lock(&irq->irq_lock);
250+
spin_lock_irqsave(&irq->irq_lock, flags);
249251
if (test_bit(i, &val)) {
250252
/*
251253
* pending_latch is set irrespective of irq type
252254
* (level or edge) to avoid dependency that VM should
253255
* restore irq config before pending info.
254256
*/
255257
irq->pending_latch = true;
256-
vgic_queue_irq_unlock(vcpu->kvm, irq);
258+
vgic_queue_irq_unlock(vcpu->kvm, irq, flags);
257259
} else {
258260
irq->pending_latch = false;
259-
spin_unlock(&irq->irq_lock);
261+
spin_unlock_irqrestore(&irq->irq_lock, flags);
260262
}
261263

262264
vgic_put_irq(vcpu->kvm, irq);
@@ -799,6 +801,7 @@ void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg)
799801
int sgi, c;
800802
int vcpu_id = vcpu->vcpu_id;
801803
bool broadcast;
804+
unsigned long flags;
802805

803806
sgi = (reg & ICC_SGI1R_SGI_ID_MASK) >> ICC_SGI1R_SGI_ID_SHIFT;
804807
broadcast = reg & BIT_ULL(ICC_SGI1R_IRQ_ROUTING_MODE_BIT);
@@ -837,10 +840,10 @@ void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg)
837840

838841
irq = vgic_get_irq(vcpu->kvm, c_vcpu, sgi);
839842

840-
spin_lock(&irq->irq_lock);
843+
spin_lock_irqsave(&irq->irq_lock, flags);
841844
irq->pending_latch = true;
842845

843-
vgic_queue_irq_unlock(vcpu->kvm, irq);
846+
vgic_queue_irq_unlock(vcpu->kvm, irq, flags);
844847
vgic_put_irq(vcpu->kvm, irq);
845848
}
846849
}

virt/kvm/arm/vgic/vgic-mmio.c

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -69,13 +69,14 @@ void vgic_mmio_write_senable(struct kvm_vcpu *vcpu,
6969
{
7070
u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
7171
int i;
72+
unsigned long flags;
7273

7374
for_each_set_bit(i, &val, len * 8) {
7475
struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
7576

76-
spin_lock(&irq->irq_lock);
77+
spin_lock_irqsave(&irq->irq_lock, flags);
7778
irq->enabled = true;
78-
vgic_queue_irq_unlock(vcpu->kvm, irq);
79+
vgic_queue_irq_unlock(vcpu->kvm, irq, flags);
7980

8081
vgic_put_irq(vcpu->kvm, irq);
8182
}
@@ -87,15 +88,16 @@ void vgic_mmio_write_cenable(struct kvm_vcpu *vcpu,
8788
{
8889
u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
8990
int i;
91+
unsigned long flags;
9092

9193
for_each_set_bit(i, &val, len * 8) {
9294
struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
9395

94-
spin_lock(&irq->irq_lock);
96+
spin_lock_irqsave(&irq->irq_lock, flags);
9597

9698
irq->enabled = false;
9799

98-
spin_unlock(&irq->irq_lock);
100+
spin_unlock_irqrestore(&irq->irq_lock, flags);
99101
vgic_put_irq(vcpu->kvm, irq);
100102
}
101103
}
@@ -126,14 +128,15 @@ void vgic_mmio_write_spending(struct kvm_vcpu *vcpu,
126128
{
127129
u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
128130
int i;
131+
unsigned long flags;
129132

130133
for_each_set_bit(i, &val, len * 8) {
131134
struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
132135

133-
spin_lock(&irq->irq_lock);
136+
spin_lock_irqsave(&irq->irq_lock, flags);
134137
irq->pending_latch = true;
135138

136-
vgic_queue_irq_unlock(vcpu->kvm, irq);
139+
vgic_queue_irq_unlock(vcpu->kvm, irq, flags);
137140
vgic_put_irq(vcpu->kvm, irq);
138141
}
139142
}
@@ -144,15 +147,16 @@ void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
144147
{
145148
u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
146149
int i;
150+
unsigned long flags;
147151

148152
for_each_set_bit(i, &val, len * 8) {
149153
struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
150154

151-
spin_lock(&irq->irq_lock);
155+
spin_lock_irqsave(&irq->irq_lock, flags);
152156

153157
irq->pending_latch = false;
154158

155-
spin_unlock(&irq->irq_lock);
159+
spin_unlock_irqrestore(&irq->irq_lock, flags);
156160
vgic_put_irq(vcpu->kvm, irq);
157161
}
158162
}
@@ -181,7 +185,8 @@ static void vgic_mmio_change_active(struct kvm_vcpu *vcpu, struct vgic_irq *irq,
181185
bool new_active_state)
182186
{
183187
struct kvm_vcpu *requester_vcpu;
184-
spin_lock(&irq->irq_lock);
188+
unsigned long flags;
189+
spin_lock_irqsave(&irq->irq_lock, flags);
185190

186191
/*
187192
* The vcpu parameter here can mean multiple things depending on how
@@ -216,9 +221,9 @@ static void vgic_mmio_change_active(struct kvm_vcpu *vcpu, struct vgic_irq *irq,
216221

217222
irq->active = new_active_state;
218223
if (new_active_state)
219-
vgic_queue_irq_unlock(vcpu->kvm, irq);
224+
vgic_queue_irq_unlock(vcpu->kvm, irq, flags);
220225
else
221-
spin_unlock(&irq->irq_lock);
226+
spin_unlock_irqrestore(&irq->irq_lock, flags);
222227
}
223228

224229
/*
@@ -352,14 +357,15 @@ void vgic_mmio_write_priority(struct kvm_vcpu *vcpu,
352357
{
353358
u32 intid = VGIC_ADDR_TO_INTID(addr, 8);
354359
int i;
360+
unsigned long flags;
355361

356362
for (i = 0; i < len; i++) {
357363
struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
358364

359-
spin_lock(&irq->irq_lock);
365+
spin_lock_irqsave(&irq->irq_lock, flags);
360366
/* Narrow the priority range to what we actually support */
361367
irq->priority = (val >> (i * 8)) & GENMASK(7, 8 - VGIC_PRI_BITS);
362-
spin_unlock(&irq->irq_lock);
368+
spin_unlock_irqrestore(&irq->irq_lock, flags);
363369

364370
vgic_put_irq(vcpu->kvm, irq);
365371
}
@@ -390,6 +396,7 @@ void vgic_mmio_write_config(struct kvm_vcpu *vcpu,
390396
{
391397
u32 intid = VGIC_ADDR_TO_INTID(addr, 2);
392398
int i;
399+
unsigned long flags;
393400

394401
for (i = 0; i < len * 4; i++) {
395402
struct vgic_irq *irq;
@@ -404,14 +411,14 @@ void vgic_mmio_write_config(struct kvm_vcpu *vcpu,
404411
continue;
405412

406413
irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
407-
spin_lock(&irq->irq_lock);
414+
spin_lock_irqsave(&irq->irq_lock, flags);
408415

409416
if (test_bit(i * 2 + 1, &val))
410417
irq->config = VGIC_CONFIG_EDGE;
411418
else
412419
irq->config = VGIC_CONFIG_LEVEL;
413420

414-
spin_unlock(&irq->irq_lock);
421+
spin_unlock_irqrestore(&irq->irq_lock, flags);
415422
vgic_put_irq(vcpu->kvm, irq);
416423
}
417424
}
@@ -443,6 +450,7 @@ void vgic_write_irq_line_level_info(struct kvm_vcpu *vcpu, u32 intid,
443450
{
444451
int i;
445452
int nr_irqs = vcpu->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
453+
unsigned long flags;
446454

447455
for (i = 0; i < 32; i++) {
448456
struct vgic_irq *irq;
@@ -459,12 +467,12 @@ void vgic_write_irq_line_level_info(struct kvm_vcpu *vcpu, u32 intid,
459467
* restore irq config before line level.
460468
*/
461469
new_level = !!(val & (1U << i));
462-
spin_lock(&irq->irq_lock);
470+
spin_lock_irqsave(&irq->irq_lock, flags);
463471
irq->line_level = new_level;
464472
if (new_level)
465-
vgic_queue_irq_unlock(vcpu->kvm, irq);
473+
vgic_queue_irq_unlock(vcpu->kvm, irq, flags);
466474
else
467-
spin_unlock(&irq->irq_lock);
475+
spin_unlock_irqrestore(&irq->irq_lock, flags);
468476

469477
vgic_put_irq(vcpu->kvm, irq);
470478
}

0 commit comments

Comments
 (0)