Merge tag 'kvm-arm-for-4.10' of git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm into HEAD

KVM/ARM updates for 4.10:

- Support for the GICv3 ITS on 32bit platforms
- A handful of timer and GIC emulation fixes
- A PMU architecture fix
This commit is contained in:
Paolo Bonzini
2016-12-12 07:29:39 +01:00
15 changed files with 36 additions and 63 deletions

View File

@@ -2201,7 +2201,7 @@ after pausing the vcpu, but before it is resumed.
4.71 KVM_SIGNAL_MSI 4.71 KVM_SIGNAL_MSI
Capability: KVM_CAP_SIGNAL_MSI Capability: KVM_CAP_SIGNAL_MSI
Architectures: x86 arm64 Architectures: x86 arm arm64
Type: vm ioctl Type: vm ioctl
Parameters: struct kvm_msi (in) Parameters: struct kvm_msi (in)
Returns: >0 on delivery, 0 if guest blocked the MSI, and -1 on error Returns: >0 on delivery, 0 if guest blocked the MSI, and -1 on error

View File

@@ -87,9 +87,11 @@ struct kvm_regs {
/* Supported VGICv3 address types */ /* Supported VGICv3 address types */
#define KVM_VGIC_V3_ADDR_TYPE_DIST 2 #define KVM_VGIC_V3_ADDR_TYPE_DIST 2
#define KVM_VGIC_V3_ADDR_TYPE_REDIST 3 #define KVM_VGIC_V3_ADDR_TYPE_REDIST 3
#define KVM_VGIC_ITS_ADDR_TYPE 4
#define KVM_VGIC_V3_DIST_SIZE SZ_64K #define KVM_VGIC_V3_DIST_SIZE SZ_64K
#define KVM_VGIC_V3_REDIST_SIZE (2 * SZ_64K) #define KVM_VGIC_V3_REDIST_SIZE (2 * SZ_64K)
#define KVM_VGIC_V3_ITS_SIZE (2 * SZ_64K)
#define KVM_ARM_VCPU_POWER_OFF 0 /* CPU is started in OFF state */ #define KVM_ARM_VCPU_POWER_OFF 0 /* CPU is started in OFF state */
#define KVM_ARM_VCPU_PSCI_0_2 1 /* CPU uses PSCI v0.2 */ #define KVM_ARM_VCPU_PSCI_0_2 1 /* CPU uses PSCI v0.2 */

View File

@@ -34,6 +34,7 @@ config KVM
select HAVE_KVM_IRQFD select HAVE_KVM_IRQFD
select HAVE_KVM_IRQCHIP select HAVE_KVM_IRQCHIP
select HAVE_KVM_IRQ_ROUTING select HAVE_KVM_IRQ_ROUTING
select HAVE_KVM_MSI
depends on ARM_VIRT_EXT && ARM_LPAE && ARM_ARCH_TIMER depends on ARM_VIRT_EXT && ARM_LPAE && ARM_ARCH_TIMER
---help--- ---help---
Support hosting virtualized guest machines. Support hosting virtualized guest machines.

View File

@@ -32,5 +32,6 @@ obj-y += $(KVM)/arm/vgic/vgic-mmio.o
obj-y += $(KVM)/arm/vgic/vgic-mmio-v2.o obj-y += $(KVM)/arm/vgic/vgic-mmio-v2.o
obj-y += $(KVM)/arm/vgic/vgic-mmio-v3.o obj-y += $(KVM)/arm/vgic/vgic-mmio-v3.o
obj-y += $(KVM)/arm/vgic/vgic-kvm-device.o obj-y += $(KVM)/arm/vgic/vgic-kvm-device.o
obj-y += $(KVM)/arm/vgic/vgic-its.o
obj-y += $(KVM)/irqchip.o obj-y += $(KVM)/irqchip.o
obj-y += $(KVM)/arm/arch_timer.o obj-y += $(KVM)/arm/arch_timer.o

View File

@@ -221,6 +221,12 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
case KVM_CAP_MAX_VCPUS: case KVM_CAP_MAX_VCPUS:
r = KVM_MAX_VCPUS; r = KVM_MAX_VCPUS;
break; break;
case KVM_CAP_MSI_DEVID:
if (!kvm)
r = -EINVAL;
else
r = kvm->arch.vgic.msis_require_devid;
break;
default: default:
r = kvm_arch_dev_ioctl_check_extension(kvm, ext); r = kvm_arch_dev_ioctl_check_extension(kvm, ext);
break; break;

View File

@@ -16,9 +16,6 @@ menuconfig VIRTUALIZATION
if VIRTUALIZATION if VIRTUALIZATION
config KVM_ARM_VGIC_V3_ITS
bool
config KVM config KVM
bool "Kernel-based Virtual Machine (KVM) support" bool "Kernel-based Virtual Machine (KVM) support"
depends on OF depends on OF
@@ -34,7 +31,6 @@ config KVM
select KVM_VFIO select KVM_VFIO
select HAVE_KVM_EVENTFD select HAVE_KVM_EVENTFD
select HAVE_KVM_IRQFD select HAVE_KVM_IRQFD
select KVM_ARM_VGIC_V3_ITS
select KVM_ARM_PMU if HW_PERF_EVENTS select KVM_ARM_PMU if HW_PERF_EVENTS
select HAVE_KVM_MSI select HAVE_KVM_MSI
select HAVE_KVM_IRQCHIP select HAVE_KVM_IRQCHIP

View File

@@ -85,7 +85,13 @@ static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
write_sysreg(val, hcr_el2); write_sysreg(val, hcr_el2);
/* Trap on AArch32 cp15 c15 accesses (EL1 or EL0) */ /* Trap on AArch32 cp15 c15 accesses (EL1 or EL0) */
write_sysreg(1 << 15, hstr_el2); write_sysreg(1 << 15, hstr_el2);
/* Make sure we trap PMU access from EL0 to EL2 */ /*
* Make sure we trap PMU access from EL0 to EL2. Also sanitize
* PMSELR_EL0 to make sure it never contains the cycle
* counter, which could make a PMXEVCNTR_EL0 access UNDEF at
* EL1 instead of being trapped to EL2.
*/
write_sysreg(0, pmselr_el0);
write_sysreg(ARMV8_PMU_USERENR_MASK, pmuserenr_el0); write_sysreg(ARMV8_PMU_USERENR_MASK, pmuserenr_el0);
write_sysreg(vcpu->arch.mdcr_el2, mdcr_el2); write_sysreg(vcpu->arch.mdcr_el2, mdcr_el2);
__activate_traps_arch()(); __activate_traps_arch()();

View File

@@ -86,12 +86,6 @@ int kvm_arch_dev_ioctl_check_extension(struct kvm *kvm, long ext)
case KVM_CAP_VCPU_ATTRIBUTES: case KVM_CAP_VCPU_ATTRIBUTES:
r = 1; r = 1;
break; break;
case KVM_CAP_MSI_DEVID:
if (!kvm)
r = -EINVAL;
else
r = kvm->arch.vgic.msis_require_devid;
break;
default: default:
r = 0; r = 0;
} }

View File

@@ -295,10 +295,10 @@
#define GITS_BASER_InnerShareable \ #define GITS_BASER_InnerShareable \
GIC_BASER_SHAREABILITY(GITS_BASER, InnerShareable) GIC_BASER_SHAREABILITY(GITS_BASER, InnerShareable)
#define GITS_BASER_PAGE_SIZE_SHIFT (8) #define GITS_BASER_PAGE_SIZE_SHIFT (8)
#define GITS_BASER_PAGE_SIZE_4K (0UL << GITS_BASER_PAGE_SIZE_SHIFT) #define GITS_BASER_PAGE_SIZE_4K (0ULL << GITS_BASER_PAGE_SIZE_SHIFT)
#define GITS_BASER_PAGE_SIZE_16K (1UL << GITS_BASER_PAGE_SIZE_SHIFT) #define GITS_BASER_PAGE_SIZE_16K (1ULL << GITS_BASER_PAGE_SIZE_SHIFT)
#define GITS_BASER_PAGE_SIZE_64K (2UL << GITS_BASER_PAGE_SIZE_SHIFT) #define GITS_BASER_PAGE_SIZE_64K (2ULL << GITS_BASER_PAGE_SIZE_SHIFT)
#define GITS_BASER_PAGE_SIZE_MASK (3UL << GITS_BASER_PAGE_SIZE_SHIFT) #define GITS_BASER_PAGE_SIZE_MASK (3ULL << GITS_BASER_PAGE_SIZE_SHIFT)
#define GITS_BASER_PAGES_MAX 256 #define GITS_BASER_PAGES_MAX 256
#define GITS_BASER_PAGES_SHIFT (0) #define GITS_BASER_PAGES_SHIFT (0)
#define GITS_BASER_NR_PAGES(r) (((r) & 0xff) + 1) #define GITS_BASER_NR_PAGES(r) (((r) & 0xff) + 1)

View File

@@ -425,6 +425,11 @@ int kvm_timer_hyp_init(void)
info = arch_timer_get_kvm_info(); info = arch_timer_get_kvm_info();
timecounter = &info->timecounter; timecounter = &info->timecounter;
if (!timecounter->cc) {
kvm_err("kvm_arch_timer: uninitialized timecounter\n");
return -ENODEV;
}
if (info->virtual_irq <= 0) { if (info->virtual_irq <= 0) {
kvm_err("kvm_arch_timer: invalid virtual timer IRQ: %d\n", kvm_err("kvm_arch_timer: invalid virtual timer IRQ: %d\n",
info->virtual_irq); info->virtual_irq);
@@ -498,17 +503,7 @@ int kvm_timer_enable(struct kvm_vcpu *vcpu)
if (ret) if (ret)
return ret; return ret;
timer->enabled = 1;
/*
* There is a potential race here between VCPUs starting for the first
* time, which may be enabling the timer multiple times. That doesn't
* hurt though, because we're just setting a variable to the same
* variable that it already was. The important thing is that all
* VCPUs have the enabled variable set, before entering the guest, if
* the arch timers are enabled.
*/
if (timecounter)
timer->enabled = 1;
return 0; return 0;
} }

View File

@@ -632,21 +632,22 @@ static bool vgic_its_check_id(struct vgic_its *its, u64 baser, int id)
int index; int index;
u64 indirect_ptr; u64 indirect_ptr;
gfn_t gfn; gfn_t gfn;
int esz = GITS_BASER_ENTRY_SIZE(baser);
if (!(baser & GITS_BASER_INDIRECT)) { if (!(baser & GITS_BASER_INDIRECT)) {
phys_addr_t addr; phys_addr_t addr;
if (id >= (l1_tbl_size / GITS_BASER_ENTRY_SIZE(baser))) if (id >= (l1_tbl_size / esz))
return false; return false;
addr = BASER_ADDRESS(baser) + id * GITS_BASER_ENTRY_SIZE(baser); addr = BASER_ADDRESS(baser) + id * esz;
gfn = addr >> PAGE_SHIFT; gfn = addr >> PAGE_SHIFT;
return kvm_is_visible_gfn(its->dev->kvm, gfn); return kvm_is_visible_gfn(its->dev->kvm, gfn);
} }
/* calculate and check the index into the 1st level */ /* calculate and check the index into the 1st level */
index = id / (SZ_64K / GITS_BASER_ENTRY_SIZE(baser)); index = id / (SZ_64K / esz);
if (index >= (l1_tbl_size / sizeof(u64))) if (index >= (l1_tbl_size / sizeof(u64)))
return false; return false;
@@ -670,8 +671,8 @@ static bool vgic_its_check_id(struct vgic_its *its, u64 baser, int id)
indirect_ptr &= GENMASK_ULL(51, 16); indirect_ptr &= GENMASK_ULL(51, 16);
/* Find the address of the actual entry */ /* Find the address of the actual entry */
index = id % (SZ_64K / GITS_BASER_ENTRY_SIZE(baser)); index = id % (SZ_64K / esz);
indirect_ptr += index * GITS_BASER_ENTRY_SIZE(baser); indirect_ptr += index * esz;
gfn = indirect_ptr >> PAGE_SHIFT; gfn = indirect_ptr >> PAGE_SHIFT;
return kvm_is_visible_gfn(its->dev->kvm, gfn); return kvm_is_visible_gfn(its->dev->kvm, gfn);

View File

@@ -221,11 +221,9 @@ int kvm_register_vgic_device(unsigned long type)
ret = kvm_register_device_ops(&kvm_arm_vgic_v3_ops, ret = kvm_register_device_ops(&kvm_arm_vgic_v3_ops,
KVM_DEV_TYPE_ARM_VGIC_V3); KVM_DEV_TYPE_ARM_VGIC_V3);
#ifdef CONFIG_KVM_ARM_VGIC_V3_ITS
if (ret) if (ret)
break; break;
ret = kvm_vgic_register_its_device(); ret = kvm_vgic_register_its_device();
#endif
break; break;
} }

View File

@@ -129,6 +129,7 @@ static void vgic_mmio_write_target(struct kvm_vcpu *vcpu,
unsigned long val) unsigned long val)
{ {
u32 intid = VGIC_ADDR_TO_INTID(addr, 8); u32 intid = VGIC_ADDR_TO_INTID(addr, 8);
u8 cpu_mask = GENMASK(atomic_read(&vcpu->kvm->online_vcpus) - 1, 0);
int i; int i;
/* GICD_ITARGETSR[0-7] are read-only */ /* GICD_ITARGETSR[0-7] are read-only */
@@ -141,7 +142,7 @@ static void vgic_mmio_write_target(struct kvm_vcpu *vcpu,
spin_lock(&irq->irq_lock); spin_lock(&irq->irq_lock);
irq->targets = (val >> (i * 8)) & 0xff; irq->targets = (val >> (i * 8)) & cpu_mask;
target = irq->targets ? __ffs(irq->targets) : 0; target = irq->targets ? __ffs(irq->targets) : 0;
irq->target_vcpu = kvm_get_vcpu(vcpu->kvm, target); irq->target_vcpu = kvm_get_vcpu(vcpu->kvm, target);

View File

@@ -42,7 +42,6 @@ u64 update_64bit_reg(u64 reg, unsigned int offset, unsigned int len,
return reg | ((u64)val << lower); return reg | ((u64)val << lower);
} }
#ifdef CONFIG_KVM_ARM_VGIC_V3_ITS
bool vgic_has_its(struct kvm *kvm) bool vgic_has_its(struct kvm *kvm)
{ {
struct vgic_dist *dist = &kvm->arch.vgic; struct vgic_dist *dist = &kvm->arch.vgic;
@@ -52,7 +51,6 @@ bool vgic_has_its(struct kvm *kvm)
return dist->has_its; return dist->has_its;
} }
#endif
static unsigned long vgic_mmio_read_v3_misc(struct kvm_vcpu *vcpu, static unsigned long vgic_mmio_read_v3_misc(struct kvm_vcpu *vcpu,
gpa_t addr, unsigned int len) gpa_t addr, unsigned int len)

View File

@@ -84,37 +84,11 @@ int vgic_v3_probe(const struct gic_kvm_info *info);
int vgic_v3_map_resources(struct kvm *kvm); int vgic_v3_map_resources(struct kvm *kvm);
int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t dist_base_address); int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t dist_base_address);
#ifdef CONFIG_KVM_ARM_VGIC_V3_ITS
int vgic_register_its_iodevs(struct kvm *kvm); int vgic_register_its_iodevs(struct kvm *kvm);
bool vgic_has_its(struct kvm *kvm); bool vgic_has_its(struct kvm *kvm);
int kvm_vgic_register_its_device(void); int kvm_vgic_register_its_device(void);
void vgic_enable_lpis(struct kvm_vcpu *vcpu); void vgic_enable_lpis(struct kvm_vcpu *vcpu);
int vgic_its_inject_msi(struct kvm *kvm, struct kvm_msi *msi); int vgic_its_inject_msi(struct kvm *kvm, struct kvm_msi *msi);
#else
static inline int vgic_register_its_iodevs(struct kvm *kvm)
{
return -ENODEV;
}
static inline bool vgic_has_its(struct kvm *kvm)
{
return false;
}
static inline int kvm_vgic_register_its_device(void)
{
return -ENODEV;
}
static inline void vgic_enable_lpis(struct kvm_vcpu *vcpu)
{
}
static inline int vgic_its_inject_msi(struct kvm *kvm, struct kvm_msi *msi)
{
return -ENODEV;
}
#endif
int kvm_register_vgic_device(unsigned long type); int kvm_register_vgic_device(unsigned long type);
int vgic_lazy_init(struct kvm *kvm); int vgic_lazy_init(struct kvm *kvm);