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
87static const struct irq_domain_ops *vpe_domain_ops;87static const struct irq_domain_ops *vpe_domain_ops;
88static const struct irq_domain_ops *sgi_domain_ops;88static const struct irq_domain_ops *sgi_domain_ops;
89 89
90static bool has_v4_1(void)
91{
92 return !!sgi_domain_ops;
93}
94
90int its_alloc_vcpu_irqs(struct its_vm *vm)95int its_alloc_vcpu_irqs(struct its_vm *vm)
91{96{
92 int vpe_base_irq, i;97 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
139 return irq_set_vcpu_affinity(vpe->irq, info);144 return irq_set_vcpu_affinity(vpe->irq, info);
140}145}
141 146
142int its_schedule_vpe(struct its_vpe *vpe, bool on)147int its_make_vpe_non_resident(struct its_vpe *vpe, bool db)
143{148{
144 struct its_cmd_info info;149 struct irq_desc *desc = irq_to_desc(vpe->irq);
150 struct its_cmd_info info = { };
145 int ret;151 int ret;
146 152
147 WARN_ON(preemptible());153 WARN_ON(preemptible());
148 154
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
172int 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 }
150 187
151 ret = its_send_vpe_cmd(vpe, &info);188 ret = its_send_vpe_cmd(vpe, &info);
152 if (!ret)189 if (!ret)
153 vpe->resident = on;190 vpe->resident = true;
154 191
155 return ret;192 return ret;
156}193}
include/kvm/arm_vgic.h+1−0
@@ -70,6 +70,7 @@ struct vgic_global { · 69 unmodified lines
70 70
71 /* Hardware has GICv4? */71 /* Hardware has GICv4? */
72 bool has_gicv4;72 bool has_gicv4;
73 bool has_gicv4_1;
73 74
74 /* GIC system register CPU interface */75 /* GIC system register CPU interface */
75 struct static_key_false gicv3_cpuif;76 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
125 125
126int its_alloc_vcpu_irqs(struct its_vm *vm);126int its_alloc_vcpu_irqs(struct its_vm *vm);
127void its_free_vcpu_irqs(struct its_vm *vm);127void its_free_vcpu_irqs(struct its_vm *vm);
128int its_schedule_vpe(struct its_vpe *vpe, bool on);128int its_make_vpe_resident(struct its_vpe *vpe, bool g0en, bool g1en);
129int its_make_vpe_non_resident(struct its_vpe *vpe, bool db);
129int its_invall_vpe(struct its_vpe *vpe);130int its_invall_vpe(struct its_vpe *vpe);
130int its_map_vlpi(int irq, struct its_vlpi_map *map);131int its_map_vlpi(int irq, struct its_vlpi_map *map);
131int its_get_vlpi(int irq, struct its_vlpi_map *map);132int 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
595 /* GICv4 support? */595 /* GICv4 support? */
596 if (info->has_v4) {596 if (info->has_v4) {
597 kvm_vgic_global_state.has_gicv4 = gicv4_enable;597 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" : "",
599 gicv4_enable ? "en" : "dis");601 gicv4_enable ? "en" : "dis");
600 }602 }
601 603
virt/kvm/arm/vgic/vgic-v4.c+14−20
@@ -67,10 +67,10 @@ · 66 unmodified lines
67 * it. And if we've migrated our vcpu from one CPU to another, we must67 * it. And if we've migrated our vcpu from one CPU to another, we must
68 * tell the ITS (so that the messages reach the right redistributor).68 * tell the ITS (so that the messages reach the right redistributor).
69 * This is done in two steps: first issue a irq_set_affinity() on the69 * 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(). You70 * irq corresponding to the vcpu, then call its_make_vpe_resident().
71 * must be in a non-preemptible context. On exit, another call to71 * You must be in a non-preemptible context. On exit, a call to
72 * its_schedule_vpe() tells the redistributor that we're done with the72 * its_make_vpe_non_resident() tells the redistributor that we're done
73 * vcpu.73 * with the vcpu.
74 *74 *
75 * Finally, the doorbell handling: Each vcpu is allocated an interrupt75 * Finally, the doorbell handling: Each vcpu is allocated an interrupt
76 * which will fire each time a VLPI is made pending whilst the vcpu is76 * 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
86 struct kvm_vcpu *vcpu = info;86 struct kvm_vcpu *vcpu = info;
87 87
88 /* We got the message, no need to fire again */88 /* 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))
90 disable_irq_nosync(irq);91 disable_irq_nosync(irq);
91 92
92 vcpu->arch.vgic_cpu.vgic_v3.its_vpe.pending_last = true;93 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
199int vgic_v4_put(struct kvm_vcpu *vcpu, bool need_db)200int vgic_v4_put(struct kvm_vcpu *vcpu, bool need_db)
200{201{
201 struct its_vpe *vpe = &vcpu->arch.vgic_cpu.vgic_v3.its_vpe;202 struct its_vpe *vpe = &vcpu->arch.vgic_cpu.vgic_v3.its_vpe;
202 struct irq_desc *desc = irq_to_desc(vpe->irq);
203 203
204 if (!vgic_supports_direct_msis(vcpu->kvm) || !vpe->resident)204 if (!vgic_supports_direct_msis(vcpu->kvm) || !vpe->resident)
205 return 0;205 return 0;
206 206
207 /*207 return its_make_vpe_non_resident(vpe, need_db);
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);
215}208}
216 209
217int vgic_v4_load(struct kvm_vcpu *vcpu)210int vgic_v4_load(struct kvm_vcpu *vcpu)
@@ -232,18 +225,19 @@ int vgic_v4_load(struct kvm_vcpu *vcpu) · 14 unmodified lines
232 if (err)225 if (err)
233 return err;226 return err;
234 227
235 /* Disabled the doorbell, as we're about to enter the guest */228 err = its_make_vpe_resident(vpe, false, vcpu->kvm->arch.vgic.enabled);
236 disable_irq_nosync(vpe->irq);
237
238 err = its_schedule_vpe(vpe, true);
239 if (err)229 if (err)
240 return err;230 return err;
241 231
242 /*232 /*
243 * Now that the VPE is resident, let's get rid of a potential233 * 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"...
245 */236 */
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;
247}241}
248 242
249static struct vgic_its *vgic_get_its(struct kvm *kvm,243static struct vgic_its *vgic_get_its(struct kvm *kvm,