From: christoffer.dall@linaro.org (Christoffer Dall)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH v3 7/9] KVM: arm-vgic: Support unqueueing of LRs to the dist
Date: Wed, 11 Dec 2013 21:29:31 -0800 [thread overview]
Message-ID: <20131212052931.GN2871@cbox> (raw)
In-Reply-To: <ec8aca55520ec17d0c59d63ceae63d06@www.loen.fr>
On Mon, Dec 09, 2013 at 04:38:33PM +0000, Marc Zyngier wrote:
> On 2013-11-17 04:30, Christoffer Dall wrote:
> >To properly access the VGIC state from user space it is very
> >unpractical
> >to have to loop through all the LRs in all register access functions.
> >Instead, support moving all pending state from LRs to the
> >distributor,
> >but leave active state LRs alone.
> >
> >Note that to accurately present the active and pending state to VCPUs
> >reading these distributor registers from a live VM, we would have to
> >stop all other VPUs than the calling VCPU and ask each CPU to unqueue
> >their LR state onto the distributor and add fields to track active
> >state
> >on the distributor side as well. We don't have any users of such
> >functionality yet and there are other inaccuracies of the GIC
> >emulation,
> >so don't provide accurate synchronized access to this state just yet.
> >However, when the time comes, having this function should help.
> >
> >Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> >
> >Changelog[3]:
> > - New patch in series
> >---
> > virt/kvm/arm/vgic.c | 80
> >+++++++++++++++++++++++++++++++++++++++++++++++----
> > 1 file changed, 75 insertions(+), 5 deletions(-)
> >
> >diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
> >index ecf6dcf..44c669b 100644
> >--- a/virt/kvm/arm/vgic.c
> >+++ b/virt/kvm/arm/vgic.c
> >@@ -589,6 +589,72 @@ static bool handle_mmio_sgi_reg(struct
> >kvm_vcpu *vcpu,
> > return false;
> > }
> >
> >+#define LR_CPUID(lr) \
> >+ (((lr) & GICH_LR_PHYSID_CPUID) >> GICH_LR_PHYSID_CPUID_SHIFT)
> >+#define LR_IRQID(lr) \
> >+ ((lr) & GICH_LR_VIRTUALID)
> >+
> >+static void vgic_retire_lr(int lr_nr, int irq, struct vgic_cpu
> >*vgic_cpu)
> >+{
> >+ clear_bit(lr_nr, vgic_cpu->lr_used);
> >+ vgic_cpu->vgic_lr[lr_nr] &= ~GICH_LR_STATE;
> >+ vgic_cpu->vgic_irq_lr_map[irq] = LR_EMPTY;
> >+}
> >+
> >+/**
> >+ * vgic_unqueue_irqs - move pending IRQs from LRs to the distributor
> >+ * @vgic_cpu: Pointer to the vgic_cpu struct holding the LRs
> >+ *
> >+ * Move any pending IRQs that have already been assigned to LRs
> >back to the
> >+ * emulated distributor state so that the complete emulated state
> >can be read
> >+ * from the main emulation structures without investigating the LRs.
> >+ *
> >+ * Note that IRQs in the active state in the LRs get their pending
> >state moved
> >+ * to the distributor but the active state stays in the LRs, because
> >we don't
> >+ * track the active state on the distributor side.
> >+ */
> >+static void vgic_unqueue_irqs(struct kvm_vcpu *vcpu)
> >+{
> >+ struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
> >+ struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> >+ int vcpu_id = vcpu->vcpu_id;
> >+ int i, irq, source_cpu;
> >+ u32 *lr;
> >+
> >+ for_each_set_bit(i, vgic_cpu->lr_used, vgic_cpu->nr_lr) {
> >+ lr = &vgic_cpu->vgic_lr[i];
> >+ irq = LR_IRQID(*lr);
> >+ source_cpu = LR_CPUID(*lr);
> >+
> >+ /*
> >+ * If the LR holds only an active interrupt (not pending) then
> >+ * just leave it alone.
> >+ */
> >+ if (!__test_and_clear_bit(__ffs(GICH_LR_PENDING_BIT),
> >+ (unsigned long *)lr))
> >+ continue;
>
> Now you got me confused. The comment talks about the active bit, but
> you're actually clearing the pending bit. Surely that deserves a
> better explanation.
>
Fair enough, it's not obvious. There are three options for the LR state
at this point:
01: pending
10: active
11: pending and active
so if the pending bit is clear, it means the state is "active".
But I'll change to explicitly check the state and clear the pending bit
later.
> >+
> >+ /*
> >+ * If the interrupt was only pending (not "active" or "pending
> >+ * and active") then we have effectively cleared the LR and it
> >+ * should be marked as free for other use.
> >+ */
> >+ if (!(*lr & GICH_LR_STATE))
> >+ vgic_retire_lr(i, irq, vgic_cpu);
>
> Why not directly testing the active bit? It'd be more consistent
> with the above if you used a similar method.
>
Because then it's more obvious to everyone what's going on, which is
clearly a bad thing ;)
> >+ /*
> >+ * Finally, reestablish the pending state on the distributor
> >+ * and the CPU interface. It may have already been pending,
> >+ * but that is fine, then we are only setting a few bits that
> >+ * were already set.
> >+ */
> >+ vgic_dist_irq_set(vcpu, irq);
> >+ if (irq < VGIC_NR_SGIS)
> >+ dist->irq_sgi_sources[vcpu_id][irq] |= 1 << source_cpu;
> >+ vgic_update_state(vcpu->kvm);
> >+ }
> >+}
> >+
> > static bool handle_mmio_sgi_clear(struct kvm_vcpu *vcpu,
> > struct kvm_exit_mmio *mmio,
> > phys_addr_t offset)
> >@@ -848,8 +914,6 @@ static void vgic_update_state(struct kvm *kvm)
> > }
> > }
> >
> >-#define LR_CPUID(lr) \
> >- (((lr) & GICH_LR_PHYSID_CPUID) >> GICH_LR_PHYSID_CPUID_SHIFT)
> > #define MK_LR_PEND(src, irq) \
> > (GICH_LR_PENDING_BIT | ((src) << GICH_LR_PHYSID_CPUID_SHIFT) |
> >(irq))
> >
> >@@ -871,9 +935,7 @@ static void vgic_retire_disabled_irqs(struct
> >kvm_vcpu *vcpu)
> > int irq = vgic_cpu->vgic_lr[lr] & GICH_LR_VIRTUALID;
> >
> > if (!vgic_irq_is_enabled(vcpu, irq)) {
> >- vgic_cpu->vgic_irq_lr_map[irq] = LR_EMPTY;
> >- clear_bit(lr, vgic_cpu->lr_used);
> >- vgic_cpu->vgic_lr[lr] &= ~GICH_LR_STATE;
> >+ vgic_retire_lr(lr, irq, vgic_cpu);
> > if (vgic_irq_is_active(vcpu, irq))
> > vgic_irq_clear_active(vcpu, irq);
> > }
> >@@ -1664,6 +1726,14 @@ static int vgic_attr_regs_access(struct
> >kvm_device *dev,
> > }
> > }
> >
> >+ /*
> >+ * Move all pending IRQs from the LRs on all VCPUs so the pending
> >+ * state can be properly represented in the register state
> >accessible
> >+ * through this API.
> >+ */
> >+ kvm_for_each_vcpu(c, tmp_vcpu, dev->kvm)
> >+ vgic_unqueue_irqs(tmp_vcpu);
> >+
> > offset -= r->base;
> > r->handle_mmio(vcpu, &mmio, offset);
> > spin_unlock(&vgic->lock);
>
Thanks!
--
Christoffer
WARNING: multiple messages have this Message-ID (diff)
From: Christoffer Dall <christoffer.dall@linaro.org>
To: Marc Zyngier <marc.zyngier@arm.com>
Cc: kvmarm@lists.cs.columbia.edu, kvm@vger.kernel.org,
linux-arm-kernel@lists.infradead.org, patches@linaro.org
Subject: Re: [PATCH v3 7/9] KVM: arm-vgic: Support unqueueing of LRs to the dist
Date: Wed, 11 Dec 2013 21:29:31 -0800 [thread overview]
Message-ID: <20131212052931.GN2871@cbox> (raw)
In-Reply-To: <ec8aca55520ec17d0c59d63ceae63d06@www.loen.fr>
On Mon, Dec 09, 2013 at 04:38:33PM +0000, Marc Zyngier wrote:
> On 2013-11-17 04:30, Christoffer Dall wrote:
> >To properly access the VGIC state from user space it is very
> >unpractical
> >to have to loop through all the LRs in all register access functions.
> >Instead, support moving all pending state from LRs to the
> >distributor,
> >but leave active state LRs alone.
> >
> >Note that to accurately present the active and pending state to VCPUs
> >reading these distributor registers from a live VM, we would have to
> >stop all other VPUs than the calling VCPU and ask each CPU to unqueue
> >their LR state onto the distributor and add fields to track active
> >state
> >on the distributor side as well. We don't have any users of such
> >functionality yet and there are other inaccuracies of the GIC
> >emulation,
> >so don't provide accurate synchronized access to this state just yet.
> >However, when the time comes, having this function should help.
> >
> >Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> >
> >Changelog[3]:
> > - New patch in series
> >---
> > virt/kvm/arm/vgic.c | 80
> >+++++++++++++++++++++++++++++++++++++++++++++++----
> > 1 file changed, 75 insertions(+), 5 deletions(-)
> >
> >diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
> >index ecf6dcf..44c669b 100644
> >--- a/virt/kvm/arm/vgic.c
> >+++ b/virt/kvm/arm/vgic.c
> >@@ -589,6 +589,72 @@ static bool handle_mmio_sgi_reg(struct
> >kvm_vcpu *vcpu,
> > return false;
> > }
> >
> >+#define LR_CPUID(lr) \
> >+ (((lr) & GICH_LR_PHYSID_CPUID) >> GICH_LR_PHYSID_CPUID_SHIFT)
> >+#define LR_IRQID(lr) \
> >+ ((lr) & GICH_LR_VIRTUALID)
> >+
> >+static void vgic_retire_lr(int lr_nr, int irq, struct vgic_cpu
> >*vgic_cpu)
> >+{
> >+ clear_bit(lr_nr, vgic_cpu->lr_used);
> >+ vgic_cpu->vgic_lr[lr_nr] &= ~GICH_LR_STATE;
> >+ vgic_cpu->vgic_irq_lr_map[irq] = LR_EMPTY;
> >+}
> >+
> >+/**
> >+ * vgic_unqueue_irqs - move pending IRQs from LRs to the distributor
> >+ * @vgic_cpu: Pointer to the vgic_cpu struct holding the LRs
> >+ *
> >+ * Move any pending IRQs that have already been assigned to LRs
> >back to the
> >+ * emulated distributor state so that the complete emulated state
> >can be read
> >+ * from the main emulation structures without investigating the LRs.
> >+ *
> >+ * Note that IRQs in the active state in the LRs get their pending
> >state moved
> >+ * to the distributor but the active state stays in the LRs, because
> >we don't
> >+ * track the active state on the distributor side.
> >+ */
> >+static void vgic_unqueue_irqs(struct kvm_vcpu *vcpu)
> >+{
> >+ struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
> >+ struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> >+ int vcpu_id = vcpu->vcpu_id;
> >+ int i, irq, source_cpu;
> >+ u32 *lr;
> >+
> >+ for_each_set_bit(i, vgic_cpu->lr_used, vgic_cpu->nr_lr) {
> >+ lr = &vgic_cpu->vgic_lr[i];
> >+ irq = LR_IRQID(*lr);
> >+ source_cpu = LR_CPUID(*lr);
> >+
> >+ /*
> >+ * If the LR holds only an active interrupt (not pending) then
> >+ * just leave it alone.
> >+ */
> >+ if (!__test_and_clear_bit(__ffs(GICH_LR_PENDING_BIT),
> >+ (unsigned long *)lr))
> >+ continue;
>
> Now you got me confused. The comment talks about the active bit, but
> you're actually clearing the pending bit. Surely that deserves a
> better explanation.
>
Fair enough, it's not obvious. There are three options for the LR state
at this point:
01: pending
10: active
11: pending and active
so if the pending bit is clear, it means the state is "active".
But I'll change to explicitly check the state and clear the pending bit
later.
> >+
> >+ /*
> >+ * If the interrupt was only pending (not "active" or "pending
> >+ * and active") then we have effectively cleared the LR and it
> >+ * should be marked as free for other use.
> >+ */
> >+ if (!(*lr & GICH_LR_STATE))
> >+ vgic_retire_lr(i, irq, vgic_cpu);
>
> Why not directly testing the active bit? It'd be more consistent
> with the above if you used a similar method.
>
Because then it's more obvious to everyone what's going on, which is
clearly a bad thing ;)
> >+ /*
> >+ * Finally, reestablish the pending state on the distributor
> >+ * and the CPU interface. It may have already been pending,
> >+ * but that is fine, then we are only setting a few bits that
> >+ * were already set.
> >+ */
> >+ vgic_dist_irq_set(vcpu, irq);
> >+ if (irq < VGIC_NR_SGIS)
> >+ dist->irq_sgi_sources[vcpu_id][irq] |= 1 << source_cpu;
> >+ vgic_update_state(vcpu->kvm);
> >+ }
> >+}
> >+
> > static bool handle_mmio_sgi_clear(struct kvm_vcpu *vcpu,
> > struct kvm_exit_mmio *mmio,
> > phys_addr_t offset)
> >@@ -848,8 +914,6 @@ static void vgic_update_state(struct kvm *kvm)
> > }
> > }
> >
> >-#define LR_CPUID(lr) \
> >- (((lr) & GICH_LR_PHYSID_CPUID) >> GICH_LR_PHYSID_CPUID_SHIFT)
> > #define MK_LR_PEND(src, irq) \
> > (GICH_LR_PENDING_BIT | ((src) << GICH_LR_PHYSID_CPUID_SHIFT) |
> >(irq))
> >
> >@@ -871,9 +935,7 @@ static void vgic_retire_disabled_irqs(struct
> >kvm_vcpu *vcpu)
> > int irq = vgic_cpu->vgic_lr[lr] & GICH_LR_VIRTUALID;
> >
> > if (!vgic_irq_is_enabled(vcpu, irq)) {
> >- vgic_cpu->vgic_irq_lr_map[irq] = LR_EMPTY;
> >- clear_bit(lr, vgic_cpu->lr_used);
> >- vgic_cpu->vgic_lr[lr] &= ~GICH_LR_STATE;
> >+ vgic_retire_lr(lr, irq, vgic_cpu);
> > if (vgic_irq_is_active(vcpu, irq))
> > vgic_irq_clear_active(vcpu, irq);
> > }
> >@@ -1664,6 +1726,14 @@ static int vgic_attr_regs_access(struct
> >kvm_device *dev,
> > }
> > }
> >
> >+ /*
> >+ * Move all pending IRQs from the LRs on all VCPUs so the pending
> >+ * state can be properly represented in the register state
> >accessible
> >+ * through this API.
> >+ */
> >+ kvm_for_each_vcpu(c, tmp_vcpu, dev->kvm)
> >+ vgic_unqueue_irqs(tmp_vcpu);
> >+
> > offset -= r->base;
> > r->handle_mmio(vcpu, &mmio, offset);
> > spin_unlock(&vgic->lock);
>
Thanks!
--
Christoffer
next prev parent reply other threads:[~2013-12-12 5:29 UTC|newest]
Thread overview: 48+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-11-17 4:30 [PATCH v3 0/9] Support VGIC save/restore using device control API Christoffer Dall
2013-11-17 4:30 ` Christoffer Dall
2013-11-17 4:30 ` [PATCH v3 1/9] ARM: KVM: Allow creating the VGIC after VCPUs Christoffer Dall
2013-11-17 4:30 ` Christoffer Dall
2013-12-09 15:11 ` Marc Zyngier
2013-12-09 15:11 ` Marc Zyngier
2013-11-17 4:30 ` [PATCH v3 2/9] KVM: arm-vgic: Support KVM_CREATE_DEVICE for VGIC Christoffer Dall
2013-11-17 4:30 ` Christoffer Dall
2013-12-09 15:19 ` Marc Zyngier
2013-12-09 15:19 ` Marc Zyngier
2013-12-12 5:29 ` Christoffer Dall
2013-12-12 5:29 ` Christoffer Dall
2013-11-17 4:30 ` [PATCH v3 3/9] KVM: arm-vgic: Set base addr through device API Christoffer Dall
2013-11-17 4:30 ` Christoffer Dall
2013-12-09 15:38 ` Marc Zyngier
2013-12-09 15:38 ` Marc Zyngier
2013-12-12 5:29 ` Christoffer Dall
2013-12-12 5:29 ` Christoffer Dall
2013-11-17 4:30 ` [PATCH v3 4/9] irqchip: arm-gic: Define additional MMIO offsets and masks Christoffer Dall
2013-11-17 4:30 ` Christoffer Dall
2013-12-09 15:40 ` Marc Zyngier
2013-12-09 15:40 ` Marc Zyngier
2013-11-17 4:30 ` [PATCH v3 5/9] KVM: arm-vgic: Make vgic mmio functions more generic Christoffer Dall
2013-11-17 4:30 ` Christoffer Dall
2013-12-09 15:47 ` Marc Zyngier
2013-12-09 15:47 ` Marc Zyngier
2013-11-17 4:30 ` [PATCH v3 6/9] KVM: arm-vgic: Add vgic reg access from dev attr Christoffer Dall
2013-11-17 4:30 ` Christoffer Dall
2013-12-09 16:02 ` Marc Zyngier
2013-12-09 16:02 ` Marc Zyngier
2013-12-12 5:29 ` Christoffer Dall
2013-12-12 5:29 ` Christoffer Dall
2013-11-17 4:30 ` [PATCH v3 7/9] KVM: arm-vgic: Support unqueueing of LRs to the dist Christoffer Dall
2013-11-17 4:30 ` Christoffer Dall
2013-12-09 16:38 ` Marc Zyngier
2013-12-09 16:38 ` Marc Zyngier
2013-12-12 5:29 ` Christoffer Dall [this message]
2013-12-12 5:29 ` Christoffer Dall
2013-11-17 4:30 ` [PATCH v3 8/9] KVM: arm-vgic: Add GICD_SPENDSGIR and GICD_CPENDSGIR handlers Christoffer Dall
2013-11-17 4:30 ` Christoffer Dall
2013-12-09 16:49 ` Marc Zyngier
2013-12-09 16:49 ` Marc Zyngier
2013-12-12 5:29 ` Christoffer Dall
2013-12-12 5:29 ` Christoffer Dall
2013-11-17 4:30 ` [PATCH v3 9/9] KVM: arm-vgic: Support CPU interface reg access Christoffer Dall
2013-11-17 4:30 ` Christoffer Dall
2013-12-09 17:13 ` Marc Zyngier
2013-12-09 17:13 ` Marc Zyngier
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20131212052931.GN2871@cbox \
--to=christoffer.dall@linaro.org \
--cc=linux-arm-kernel@lists.infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.