[PATCH v4 15/19] arm/arm64: KVM: add virtual GICv3 distributor emulation
Christoffer Dall
christoffer.dall at linaro.org
Tue Nov 25 02:41:29 PST 2014
Hi Andre,
On Mon, Nov 24, 2014 at 04:00:46PM +0000, Andre Przywara wrote:
[...]
> >> +
> >> +/*
> >> + * As this implementation does not provide compatibility
> >> + * with GICv2 (ARE==1), we report zero CPUs in bits [5..7].
> >> + * Also LPIs and MBIs are not supported, so we set the respective bits to 0.
> >> + * Also we report at most 2**10=1024 interrupt IDs (to match 1024 SPIs).
> >> + */
> >> +#define INTERRUPT_ID_BITS 10
> >> +static bool handle_mmio_typer(struct kvm_vcpu *vcpu,
> >> + struct kvm_exit_mmio *mmio, phys_addr_t offset)
> >> +{
> >> + u32 reg;
> >> +
> >> + /* we report at most 1024 IRQs via this interface */
> >
> > hmmm, do we need to repeat ourselves here?
>
> Actually ... not.
> To avoid confusion, I will probably just drop this comment.
>
> > I get a bit confused by both the comment above and here, as to *why* we
> > are reporting this value? And what is the bit about 'this interface'?
>
> With this interface I meant the number of SPIs which is communicated
> here in a GICv2 compatible way (ITLinesNumber). Looking forward to LPI
> support I didn't want to use the term IRQ without some confinement.
>
> > Is there another interface.
>
> IDbits, but admittedly this isn't clear from the comment.
> Not sure if that justifies more comments before we add ITS support, though.
>
> > Perhaps what you're trying to get at here are the semantic differences
> > between ITLinesNumber and IDbits and how that helps a reader understand
> > the code.
>
> I can add a better comment.
>
I think you just need to clarify the comment above the function or let
the code speak for itself.
> >> + reg = (min(vcpu->kvm->arch.vgic.nr_irqs, 1024) >> 5) - 1;
> >> +
> >> + reg |= (INTERRUPT_ID_BITS - 1) << 19;
> >> +
> >> + vgic_reg_access(mmio, ®, offset,
> >> + ACCESS_READ_VALUE | ACCESS_WRITE_IGNORED);
> >> +
> >> + return false;
> >> +}
> >> +
[...]
> >> + * Store the original MPIDR value in an extra array to support read-as-written.
> >> + * Unallocated MPIDRs are translated to a special value and caught
> >> + * before any array accesses.
> >
> > We may have covered this already, but why can't we restore the original
> > MPIDR based on the the irq_spi_cpu array?
> >
> > Is that because we loose information about 'which' unallocated MPIDR was
> > written?
>
> Yes.
>
> > If that's the case, it seems weird that we go through the
> > trouble but we anyway throw away the aff3 field...?
>
> Not supporting the aff3 field saves us from caring about atomicity on
> GICD_IROUTER accesses (where aff3 is in the upper word of this 64-bit
> register).
> Not supporting Aff3 is an architectural option in the GICv3, so this
> seems like a viable solution.
> I had some code to support "real" 64-bit accesses, which would allow
> Aff3 support, but have to fight this through Marc first sometimes in the
> future again ;-)
>
didn't realize it was an architecturally allowed option to not support
Aff3, in that case it's not worth the bother at this point.
> >> + */
> >> +static bool handle_mmio_route_reg(struct kvm_vcpu *vcpu,
> >> + struct kvm_exit_mmio *mmio,
> >> + phys_addr_t offset)
> >> +{
> >> + struct kvm *kvm = vcpu->kvm;
> >> + struct vgic_dist *dist = &kvm->arch.vgic;
> >> + int spi;
> >> + u32 reg;
> >> + int vcpu_id;
> >> + unsigned long *bmap, mpidr;
> >> +
> >> + /*
> >> + * The upper 32 bits of each 64 bit register are zero,
> >> + * as we don't support Aff3.
> >> + */
> >> + if ((offset & 4)) {
> >> + vgic_reg_access(mmio, NULL, offset,
> >> + ACCESS_READ_RAZ | ACCESS_WRITE_IGNORED);
> >> + return false;
> >> + }
> >> +
> >> + /* This region only covers SPIs, so no handling of private IRQs here. */
> >> + spi = offset / 8;
> >
> > that's not how I read the spec, it says that GICD_IROUTER0 to
> > GICD_IROUTER1 are not implemented (because they are SGIs and PPIs), and
> > I read the 'SPI ID m' as the lowest numbered SPI ID being 32, thus you
> > should do:
> >
> > spi = offset / 8 - VGIC_NR_PRIVATE_IRQS;
>
> Well, below I changed the description of the IROUTER range to:
oh, now it's finally coming back together for me, I think I
misunderstodd your point from last rounds of review because I didn't
realize that GICD_IROUTER was defined as 0x6000 (which I actually think
is a bit backwards, but this is not the place or time).
> + {
> + .base = GICD_IROUTER + 0x100,
> + .len = 0x1edc,
in that case, len should be 0x1ee0:
$ printf '0x%x\n' $(( (0x7fd8 + 8) - 0x6100 ))
> + .bits_per_irq = 64,
> + .handle_mmio = handle_mmio_route_reg,
> + },
>
> This was due to a comment on v3 by you, where you correctly stated the
> difference in the spec's description between IROUTER and the other
> registers regarding the private IRQ handling (not implemented/reserved
> vs. RAZ/WI).
>
> So the offset in this function is relative to 0x6100 and thus depicts
> directly the SPI number.
>
got it now, yes, the code is correct.
[...]
> >> +
> >> +/*
> >> + * This function splits accesses between the distributor and the two
> >> + * redistributor parts (private/SPI). As each redistributor is accessible
> >> + * from any CPU, we have to determine the affected VCPU by taking the faulting
> >> + * address into account. We then pass this VCPU to the handler function via
> >> + * the private parameter.
> >> + */
> >> +#define SGI_BASE_OFFSET SZ_64K
> >> +static bool vgic_v3_handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *run,
> >> + struct kvm_exit_mmio *mmio)
> >> +{
> >> + struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
> >> + unsigned long dbase = dist->vgic_dist_base;
> >> + unsigned long rdbase = dist->vgic_redist_base;
> >> + int nrcpus = atomic_read(&vcpu->kvm->online_vcpus);
> >> + int vcpu_id;
> >> + const struct kvm_mmio_range *mmio_range;
> >> +
> >> + if (is_in_range(mmio->phys_addr, mmio->len, dbase, GIC_V3_DIST_SIZE)) {
> >> + return vgic_handle_mmio_range(vcpu, run, mmio,
> >> + vgic_v3_dist_ranges, dbase);
> >> + }
> >> +
> >> + if (!is_in_range(mmio->phys_addr, mmio->len, rdbase,
> >> + GIC_V3_REDIST_SIZE * nrcpus))
> >> + return false;
> >
> > Did you think more about the contiguous allocation issue here or can you
> > give me a pointer to the requirement in the spec?
>
> 5.4.1 Re-Distributor Addressing
>
Section 5.4.1 talks about the pages within a single re-distributor having
to be contiguous, not all the re-deistributor regions having to be
contiguous, right?
> >> +
> >> +static int vgic_v3_init(struct kvm *kvm, const struct vgic_params *params)
> >> +{
> >> + struct vgic_dist *dist = &kvm->arch.vgic;
> >> + int ret, i;
> >> + u32 mpidr;
> >> +
> >> + if (IS_VGIC_ADDR_UNDEF(dist->vgic_dist_base) ||
> >> + IS_VGIC_ADDR_UNDEF(dist->vgic_redist_base)) {
> >> + kvm_err("Need to set vgic distributor addresses first\n");
> >> + return -ENXIO;
> >> + }
> >> +
> >> + /*
> >> + * FIXME: this should be moved to init_maps time, and may bite
> >> + * us when adding save/restore. Add a per-emulation hook?
> >> + */
> >
> > progress on this fixme?
>
> Progress supplies the ISS, but not this piece of code (read: none) ;-)
> I am more in favour of a follow-up patch on this one ...
hmmm, I'm not a fan of merging code with this kind of a comment in it,
because it looks scary, and I dont' really understand the problem from
just reading the comment, so something needs to be done here.
Thanks,
-Christoffer
More information about the linux-arm-kernel
mailing list