Skip to content

Commit ae699ad

Browse files
author
Marc Zyngier
committed
irqchip/gic-v4.1: Move doorbell management to the GICv4 abstraction layer
In order to hide some of the differences between v4.0 and v4.1, move the doorbell management out of the KVM code, and into the GICv4-specific layer. This allows the calling code to ask for the doorbell when blocking, and otherwise to leave the doorbell permanently disabled. This matches the v4.1 code perfectly, and only results in a minor refactoring of the v4.0 code. Signed-off-by: Marc Zyngier <maz@kernel.org> Reviewed-by: Zenghui Yu <yuzenghui@huawei.com> Link: https://lore.kernel.org/r/20200304203330.4967-14-maz@kernel.org
1 parent 05d32df commit ae699ad

File tree

5 files changed

+61
-26
lines changed

5 files changed

+61
-26
lines changed

drivers/irqchip/irq-gic-v4.c

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,11 @@ static struct irq_domain *gic_domain;
8787
static const struct irq_domain_ops *vpe_domain_ops;
8888
static const struct irq_domain_ops *sgi_domain_ops;
8989

90+
static bool has_v4_1(void)
91+
{
92+
return !!sgi_domain_ops;
93+
}
94+
9095
int its_alloc_vcpu_irqs(struct its_vm *vm)
9196
{
9297
int vpe_base_irq, i;
@@ -139,18 +144,50 @@ static int its_send_vpe_cmd(struct its_vpe *vpe, struct its_cmd_info *info)
139144
return irq_set_vcpu_affinity(vpe->irq, info);
140145
}
141146

142-
int its_schedule_vpe(struct its_vpe *vpe, bool on)
147+
int its_make_vpe_non_resident(struct its_vpe *vpe, bool db)
143148
{
144-
struct its_cmd_info info;
149+
struct irq_desc *desc = irq_to_desc(vpe->irq);
150+
struct its_cmd_info info = { };
145151
int ret;
146152

147153
WARN_ON(preemptible());
148154

149-
info.cmd_type = on ? SCHEDULE_VPE : DESCHEDULE_VPE;
155+
info.cmd_type = DESCHEDULE_VPE;
156+
if (has_v4_1()) {
157+
/* GICv4.1 can directly deal with doorbells */
158+
info.req_db = db;
159+
} else {
160+
/* Undo the nested disable_irq() calls... */
161+
while (db && irqd_irq_disabled(&desc->irq_data))
162+
enable_irq(vpe->irq);
163+
}
164+
165+
ret = its_send_vpe_cmd(vpe, &info);
166+
if (!ret)
167+
vpe->resident = false;
168+
169+
return ret;
170+
}
171+
172+
int its_make_vpe_resident(struct its_vpe *vpe, bool g0en, bool g1en)
173+
{
174+
struct its_cmd_info info = { };
175+
int ret;
176+
177+
WARN_ON(preemptible());
178+
179+
info.cmd_type = SCHEDULE_VPE;
180+
if (has_v4_1()) {
181+
info.g0en = g0en;
182+
info.g1en = g1en;
183+
} else {
184+
/* Disabled the doorbell, as we're about to enter the guest */
185+
disable_irq_nosync(vpe->irq);
186+
}
150187

151188
ret = its_send_vpe_cmd(vpe, &info);
152189
if (!ret)
153-
vpe->resident = on;
190+
vpe->resident = true;
154191

155192
return ret;
156193
}

include/kvm/arm_vgic.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ struct vgic_global {
7070

7171
/* Hardware has GICv4? */
7272
bool has_gicv4;
73+
bool has_gicv4_1;
7374

7475
/* GIC system register CPU interface */
7576
struct static_key_false gicv3_cpuif;

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,8 @@ struct its_cmd_info {
125125

126126
int its_alloc_vcpu_irqs(struct its_vm *vm);
127127
void its_free_vcpu_irqs(struct its_vm *vm);
128-
int its_schedule_vpe(struct its_vpe *vpe, bool on);
128+
int its_make_vpe_resident(struct its_vpe *vpe, bool g0en, bool g1en);
129+
int its_make_vpe_non_resident(struct its_vpe *vpe, bool db);
129130
int its_invall_vpe(struct its_vpe *vpe);
130131
int its_map_vlpi(int irq, struct its_vlpi_map *map);
131132
int its_get_vlpi(int irq, struct its_vlpi_map *map);

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -595,7 +595,9 @@ int vgic_v3_probe(const struct gic_kvm_info *info)
595595
/* GICv4 support? */
596596
if (info->has_v4) {
597597
kvm_vgic_global_state.has_gicv4 = gicv4_enable;
598-
kvm_info("GICv4 support %sabled\n",
598+
kvm_vgic_global_state.has_gicv4_1 = info->has_v4_1 && gicv4_enable;
599+
kvm_info("GICv4%s support %sabled\n",
600+
kvm_vgic_global_state.has_gicv4_1 ? ".1" : "",
599601
gicv4_enable ? "en" : "dis");
600602
}
601603

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

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,10 @@
6767
* it. And if we've migrated our vcpu from one CPU to another, we must
6868
* tell the ITS (so that the messages reach the right redistributor).
6969
* This is done in two steps: first issue a irq_set_affinity() on the
70-
* irq corresponding to the vcpu, then call its_schedule_vpe(). You
71-
* must be in a non-preemptible context. On exit, another call to
72-
* its_schedule_vpe() tells the redistributor that we're done with the
73-
* vcpu.
70+
* irq corresponding to the vcpu, then call its_make_vpe_resident().
71+
* You must be in a non-preemptible context. On exit, a call to
72+
* its_make_vpe_non_resident() tells the redistributor that we're done
73+
* with the vcpu.
7474
*
7575
* Finally, the doorbell handling: Each vcpu is allocated an interrupt
7676
* which will fire each time a VLPI is made pending whilst the vcpu is
@@ -86,7 +86,8 @@ static irqreturn_t vgic_v4_doorbell_handler(int irq, void *info)
8686
struct kvm_vcpu *vcpu = info;
8787

8888
/* We got the message, no need to fire again */
89-
if (!irqd_irq_disabled(&irq_to_desc(irq)->irq_data))
89+
if (!kvm_vgic_global_state.has_gicv4_1 &&
90+
!irqd_irq_disabled(&irq_to_desc(irq)->irq_data))
9091
disable_irq_nosync(irq);
9192

9293
vcpu->arch.vgic_cpu.vgic_v3.its_vpe.pending_last = true;
@@ -199,19 +200,11 @@ void vgic_v4_teardown(struct kvm *kvm)
199200
int vgic_v4_put(struct kvm_vcpu *vcpu, bool need_db)
200201
{
201202
struct its_vpe *vpe = &vcpu->arch.vgic_cpu.vgic_v3.its_vpe;
202-
struct irq_desc *desc = irq_to_desc(vpe->irq);
203203

204204
if (!vgic_supports_direct_msis(vcpu->kvm) || !vpe->resident)
205205
return 0;
206206

207-
/*
208-
* If blocking, a doorbell is required. Undo the nested
209-
* disable_irq() calls...
210-
*/
211-
while (need_db && irqd_irq_disabled(&desc->irq_data))
212-
enable_irq(vpe->irq);
213-
214-
return its_schedule_vpe(vpe, false);
207+
return its_make_vpe_non_resident(vpe, need_db);
215208
}
216209

217210
int vgic_v4_load(struct kvm_vcpu *vcpu)
@@ -232,18 +225,19 @@ int vgic_v4_load(struct kvm_vcpu *vcpu)
232225
if (err)
233226
return err;
234227

235-
/* Disabled the doorbell, as we're about to enter the guest */
236-
disable_irq_nosync(vpe->irq);
237-
238-
err = its_schedule_vpe(vpe, true);
228+
err = its_make_vpe_resident(vpe, false, vcpu->kvm->arch.vgic.enabled);
239229
if (err)
240230
return err;
241231

242232
/*
243233
* Now that the VPE is resident, let's get rid of a potential
244-
* doorbell interrupt that would still be pending.
234+
* doorbell interrupt that would still be pending. This is a
235+
* GICv4.0 only "feature"...
245236
*/
246-
return irq_set_irqchip_state(vpe->irq, IRQCHIP_STATE_PENDING, false);
237+
if (!kvm_vgic_global_state.has_gicv4_1)
238+
err = irq_set_irqchip_state(vpe->irq, IRQCHIP_STATE_PENDING, false);
239+
240+
return err;
247241
}
248242

249243
static struct vgic_its *vgic_get_its(struct kvm *kvm,

0 commit comments

Comments
 (0)