Hi Marc, On 04/07/2016 04:04 PM, Marc Zyngier wrote: > On 26/03/16 02:14, Andre Przywara wrote: >> The ARM GICv3 ITS emulation code goes into a separate file, but >> needs to be connected to the GICv3 emulation, of which it is an >> option. >> Introduce the skeleton with function stubs to be filled later. >> Introduce the basic ITS data structure and initialize it, but don't >> return any success yet, as we are not yet ready for the show. >> >> Signed-off-by: Andre Przywara <andre.przywara@xxxxxxx> >> --- >> arch/arm64/kvm/Makefile | 1 + >> include/kvm/vgic/vgic.h | 6 +++ >> include/linux/irqchip/arm-gic-v3.h | 1 + >> virt/kvm/arm/vgic/its-emul.c | 84 ++++++++++++++++++++++++++++++++++++++ >> virt/kvm/arm/vgic/vgic.h | 14 +++++++ >> virt/kvm/arm/vgic/vgic_init.c | 6 +++ >> virt/kvm/arm/vgic/vgic_mmio.c | 18 ++++++-- >> 7 files changed, 126 insertions(+), 4 deletions(-) >> create mode 100644 virt/kvm/arm/vgic/its-emul.c >> >> diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile >> index 2f5d431..3bec10e 100644 >> --- a/arch/arm64/kvm/Makefile >> +++ b/arch/arm64/kvm/Makefile >> @@ -28,6 +28,7 @@ kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-v2.o >> kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-v3.o >> kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic_mmio.o >> kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic_kvm_device.o >> +kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/its-emul.o >> else >> kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic.o >> kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v2.o >> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h >> index 8ea5dd7..c79bed5 100644 >> --- a/include/kvm/vgic/vgic.h >> +++ b/include/kvm/vgic/vgic.h >> @@ -112,6 +112,11 @@ struct vgic_io_device { >> struct kvm_io_device dev; >> }; >> >> +struct vgic_its { >> + bool enabled; >> + spinlock_t lock; >> +}; >> + >> struct vgic_dist { >> bool in_kernel; >> bool ready; >> @@ -153,6 +158,7 @@ struct vgic_dist { >> u64 *pendbaser; >> >> bool lpis_enabled; >> + struct vgic_its its; >> }; >> >> struct vgic_v2_cpu_if { >> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h >> index d5d798b..a813c3e 100644 >> --- a/include/linux/irqchip/arm-gic-v3.h >> +++ b/include/linux/irqchip/arm-gic-v3.h >> @@ -177,6 +177,7 @@ >> #define GITS_CWRITER 0x0088 >> #define GITS_CREADR 0x0090 >> #define GITS_BASER 0x0100 >> +#define GITS_IDREGS_BASE 0xffd0 >> #define GITS_PIDR2 GICR_PIDR2 >> >> #define GITS_TRANSLATER 0x10040 >> diff --git a/virt/kvm/arm/vgic/its-emul.c b/virt/kvm/arm/vgic/its-emul.c >> new file mode 100644 >> index 0000000..49dd5e4 >> --- /dev/null >> +++ b/virt/kvm/arm/vgic/its-emul.c >> @@ -0,0 +1,84 @@ >> +/* >> + * GICv3 ITS emulation >> + * >> + * Copyright (C) 2015 ARM Ltd. >> + * Author: Andre Przywara <andre.przywara@xxxxxxx> >> + * >> + * This program is free software; you can redistribute it and/or modify >> + * it under the terms of the GNU General Public License version 2 as >> + * published by the Free Software Foundation. >> + * >> + * This program is distributed in the hope that it will be useful, >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >> + * GNU General Public License for more details. >> + * >> + * You should have received a copy of the GNU General Public License >> + * along with this program. If not, see <http://www.gnu.org/licenses/>. >> + */ >> + >> +#include <linux/cpu.h> >> +#include <linux/kvm.h> >> +#include <linux/kvm_host.h> >> +#include <linux/interrupt.h> >> + >> +#include <linux/irqchip/arm-gic-v3.h> >> + >> +#include <asm/kvm_emulate.h> >> +#include <asm/kvm_arm.h> >> +#include <asm/kvm_mmu.h> >> + >> +#include "vgic.h" >> +#include "vgic_mmio.h" >> + >> +struct vgic_register_region its_registers[] = { >> + REGISTER_DESC_WITH_LENGTH(GITS_CTLR, >> + vgic_mmio_read_raz, vgic_mmio_write_wi, 4), >> + REGISTER_DESC_WITH_LENGTH(GITS_IIDR, >> + vgic_mmio_read_raz, vgic_mmio_write_wi, 4), >> + REGISTER_DESC_WITH_LENGTH(GITS_TYPER, >> + vgic_mmio_read_raz, vgic_mmio_write_wi, 4), > > GITS_TYPER is a 64bit register with plenty of things in the upper bits. In practice I think the 32 upper bits are reserved. Eric > >> + REGISTER_DESC_WITH_LENGTH(GITS_CBASER, >> + vgic_mmio_read_raz, vgic_mmio_write_wi, 8), >> + REGISTER_DESC_WITH_LENGTH(GITS_CWRITER, >> + vgic_mmio_read_raz, vgic_mmio_write_wi, 8), >> + REGISTER_DESC_WITH_LENGTH(GITS_CREADR, >> + vgic_mmio_read_raz, vgic_mmio_write_wi, 8), >> + REGISTER_DESC_WITH_LENGTH(GITS_BASER, >> + vgic_mmio_read_raz, vgic_mmio_write_wi, 0x40), >> + REGISTER_DESC_WITH_LENGTH(GITS_IDREGS_BASE, >> + vgic_mmio_read_raz, vgic_mmio_write_wi, 0x30), >> +}; >> + >> +/* This is called on setting the LPI enable bit in the redistributor. */ >> +void vgic_enable_lpis(struct kvm_vcpu *vcpu) >> +{ >> +} >> + >> +int vits_init(struct kvm *kvm) >> +{ >> + struct vgic_dist *dist = &kvm->arch.vgic; >> + struct vgic_its *its = &dist->its; >> + struct vgic_io_device *regions; >> + int ret, i; >> + >> + spin_lock_init(&its->lock); >> + >> + regions = kmalloc_array(ARRAY_SIZE(its_registers), >> + sizeof(struct vgic_io_device), GFP_KERNEL); >> + >> + for (i = 0; i < ARRAY_SIZE(its_registers); i++) { >> + regions[i].base_addr = dist->vgic_its_base; >> + >> + ret = kvm_vgic_register_mmio_region(kvm, NULL, >> + &its_registers[i], >> + ®ions[i], 0, false); >> + } >> + >> + if (ret) >> + return ret; >> + >> + its->enabled = false; >> + >> + return -ENXIO; >> +} >> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h >> index db9dfd7..4e7dcb8 100644 >> --- a/virt/kvm/arm/vgic/vgic.h >> +++ b/virt/kvm/arm/vgic/vgic.h >> @@ -60,6 +60,9 @@ void vgic_v3_enable(struct kvm_vcpu *vcpu); >> int vgic_v3_probe(struct device_node *vgic_node); >> int vgic_v3_map_resources(struct kvm *kvm); >> int vgic_register_redist_regions(struct kvm *kvm, gpa_t dist_base_address); >> + >> +int vits_init(struct kvm *kvm); >> +void vgic_enable_lpis(struct kvm_vcpu *vcpu); >> #else >> static inline void vgic_v3_irq_change_affinity(struct kvm *kvm, u32 intid, >> u64 mpidr) >> @@ -124,6 +127,16 @@ static inline int vgic_register_redist_regions(struct kvm *kvm, >> { >> return -ENODEV; >> } >> + >> +int vits_init(struct kvm *kvm) >> +{ >> + return 0; >> +} >> + >> +static inline void vgic_enable_lpis(struct kvm_vcpu *vcpu) >> +{ >> + return; >> +} >> #endif >> >> void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr); >> @@ -131,6 +144,7 @@ void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr); >> >> int vgic_lazy_init(struct kvm *kvm); >> int vgic_init(struct kvm *kvm); >> +int vits_init(struct kvm *kvm); >> void kvm_register_vgic_device(unsigned long type); >> >> #endif >> diff --git a/virt/kvm/arm/vgic/vgic_init.c b/virt/kvm/arm/vgic/vgic_init.c >> index 2301e03..dcfb93d 100644 >> --- a/virt/kvm/arm/vgic/vgic_init.c >> +++ b/virt/kvm/arm/vgic/vgic_init.c >> @@ -252,6 +252,12 @@ int vgic_init(struct kvm *kvm) >> if (ret) >> goto out; >> >> + if (vgic_has_its(kvm)) { >> + ret = vits_init(kvm); >> + if (ret) >> + goto out; >> + } > > You can move the vgic_has_its() test inside vits_init(). > >> + >> kvm_for_each_vcpu(i, vcpu, kvm) >> kvm_vgic_vcpu_init(vcpu); >> >> diff --git a/virt/kvm/arm/vgic/vgic_mmio.c b/virt/kvm/arm/vgic/vgic_mmio.c >> index 252b9aff..086555e 100644 >> --- a/virt/kvm/arm/vgic/vgic_mmio.c >> +++ b/virt/kvm/arm/vgic/vgic_mmio.c >> @@ -726,16 +726,26 @@ static int vgic_mmio_read_v3r_misc(struct kvm_vcpu *vcpu, >> struct kvm_io_device *this, >> gpa_t addr, int len, void *val) >> { >> - /* TODO: implement for ITS support */ >> - return vgic_mmio_read_raz(vcpu, this, addr, len, val); >> + struct vgic_dist *dist = &vcpu->kvm->arch.vgic; >> + u32 reg = dist->lpis_enabled ? GICR_CTLR_ENABLE_LPIS : 0; >> + >> + write_mask32(reg, addr & 3, len, val); >> + return 0; >> } >> >> static int vgic_mmio_write_v3r_misc(struct kvm_vcpu *vcpu, >> struct kvm_io_device *this, >> gpa_t addr, int len, const void *val) >> { >> - /* TODO: implement for ITS support */ >> - return vgic_mmio_write_wi(vcpu, this, addr, len, val); >> + struct vgic_dist *dist = &vcpu->kvm->arch.vgic; >> + u32 reg = mask32(!!dist->lpis_enabled, addr & 3, len, val); >> + >> + if (vgic_has_its(vcpu->kvm) && !dist->lpis_enabled && >> + (reg & GICR_CTLR_ENABLE_LPIS)) { >> + /* Eventually do something */ >> + } >> + >> + return 0; >> } >> >> static int vgic_mmio_read_v3r_iidr(struct kvm_vcpu *vcpu, >> > > -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html