History

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.

Marc Zyngier committed 6 years ago

Commit ae699ad1 parent 05d32df5 files · +61 −26Browse files

Unified · Split

5 files
  1. drivers/irqchip/irq-gic-v4.c +41 −4
  2. include/kvm/arm_vgic.h +1 −0
  3. include/linux/irqchip/arm-gic-v4.h +2 −1
  4. virt/kvm/arm/vgic/vgic-v3.c +3 −1
  5. virt/kvm/arm/vgic/vgic-v4.c +14 −20
drivers/irqchip/irq-gic-v4.c+41−4
@@ -87,6 +87,11 @@ static struct irq_domain *gic_domain; · 86 unmodified lines
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) · 46 unmodified lines
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+1−0
@@ -70,6 +70,7 @@ struct vgic_global { · 69 unmodified lines
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+2−1
@@ -125,7 +125,8 @@ struct its_cmd_info { · 124 unmodified lines
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+3−1
@@ -595,7 +595,9 @@ int vgic_v3_probe(const struct gic_kvm_info *info) · 594 unmodified lines
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+14−20
@@ -67,10 +67,10 @@ · 66 unmodified lines
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) · 9 unmodified lines
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) · 106 unmodified lines
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) · 14 unmodified lines
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,