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:
@@ -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
|
||||||
|
@@ -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 */
|
||||||
|
@@ -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.
|
||||||
|
@@ -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
|
||||||
|
@@ -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;
|
||||||
|
@@ -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
|
||||||
|
@@ -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()();
|
||||||
|
@@ -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;
|
||||||
}
|
}
|
||||||
|
@@ -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)
|
||||||
|
@@ -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;
|
||||||
}
|
}
|
||||||
|
@@ -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);
|
||||||
|
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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);
|
||||||
|
|
||||||
|
@@ -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)
|
||||||
|
@@ -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);
|
||||||
|
Reference in New Issue
Block a user