KVM: arm64: vgic-its: Introduce migration ABI infrastructure

We plan to support different migration ABIs, ie. characterizing
the ITS table layout format in guest RAM. For example, a new ABI
will be needed if vLPIs get supported for nested use case.

So let's introduce an array of supported ABIs (at the moment a single
ABI is supported though). The following characteristics are foreseen
to vary with the ABI: size of table entries, save/restore operation,
the way abi settings are applied.

By default the MAX_ABI_REV is applied on its creation. In subsequent
patches we will introduce a way for the userspace to change the ABI
in use.

The entry sizes now are set according to the ABI version and not
hardcoded anymore.

Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Christoffer Dall <cdall@linaro.org>
This commit is contained in:
Eric Auger 2017-04-13 09:06:20 +02:00 committed by Christoffer Dall
parent 0979bfa694
commit 71afe470e2
3 changed files with 97 additions and 4 deletions

View File

@ -162,6 +162,9 @@ struct vgic_its {
u32 creadr; u32 creadr;
u32 cwriter; u32 cwriter;
/* migration ABI revision in use */
u32 abi_rev;
/* Protects the device and collection lists */ /* Protects the device and collection lists */
struct mutex its_lock; struct mutex its_lock;
struct list_head device_list; struct list_head device_list;

View File

@ -132,6 +132,9 @@
#define GIC_BASER_SHAREABILITY(reg, type) \ #define GIC_BASER_SHAREABILITY(reg, type) \
(GIC_BASER_##type << reg##_SHAREABILITY_SHIFT) (GIC_BASER_##type << reg##_SHAREABILITY_SHIFT)
/* encode a size field of width @w containing @n - 1 units */
#define GIC_ENCODE_SZ(n, w) (((unsigned long)(n) - 1) & GENMASK_ULL(((w) - 1), 0))
#define GICR_PROPBASER_SHAREABILITY_SHIFT (10) #define GICR_PROPBASER_SHAREABILITY_SHIFT (10)
#define GICR_PROPBASER_INNER_CACHEABILITY_SHIFT (7) #define GICR_PROPBASER_INNER_CACHEABILITY_SHIFT (7)
#define GICR_PROPBASER_OUTER_CACHEABILITY_SHIFT (56) #define GICR_PROPBASER_OUTER_CACHEABILITY_SHIFT (56)
@ -232,6 +235,7 @@
#define GITS_CTLR_QUIESCENT (1U << 31) #define GITS_CTLR_QUIESCENT (1U << 31)
#define GITS_TYPER_PLPIS (1UL << 0) #define GITS_TYPER_PLPIS (1UL << 0)
#define GITS_TYPER_ITT_ENTRY_SIZE_SHIFT 4
#define GITS_TYPER_IDBITS_SHIFT 8 #define GITS_TYPER_IDBITS_SHIFT 8
#define GITS_TYPER_DEVBITS_SHIFT 13 #define GITS_TYPER_DEVBITS_SHIFT 13
#define GITS_TYPER_DEVBITS(r) ((((r) >> GITS_TYPER_DEVBITS_SHIFT) & 0x1f) + 1) #define GITS_TYPER_DEVBITS(r) ((((r) >> GITS_TYPER_DEVBITS_SHIFT) & 0x1f) + 1)
@ -290,6 +294,7 @@
#define GITS_BASER_TYPE(r) (((r) >> GITS_BASER_TYPE_SHIFT) & 7) #define GITS_BASER_TYPE(r) (((r) >> GITS_BASER_TYPE_SHIFT) & 7)
#define GITS_BASER_ENTRY_SIZE_SHIFT (48) #define GITS_BASER_ENTRY_SIZE_SHIFT (48)
#define GITS_BASER_ENTRY_SIZE(r) ((((r) >> GITS_BASER_ENTRY_SIZE_SHIFT) & 0x1f) + 1) #define GITS_BASER_ENTRY_SIZE(r) ((((r) >> GITS_BASER_ENTRY_SIZE_SHIFT) & 0x1f) + 1)
#define GITS_BASER_ENTRY_SIZE_MASK GENMASK_ULL(52, 48)
#define GITS_BASER_SHAREABILITY_SHIFT (10) #define GITS_BASER_SHAREABILITY_SHIFT (10)
#define GITS_BASER_InnerShareable \ #define GITS_BASER_InnerShareable \
GIC_BASER_SHAREABILITY(GITS_BASER, InnerShareable) GIC_BASER_SHAREABILITY(GITS_BASER, InnerShareable)

View File

@ -33,6 +33,10 @@
#include "vgic.h" #include "vgic.h"
#include "vgic-mmio.h" #include "vgic-mmio.h"
static int vgic_its_save_tables_v0(struct vgic_its *its);
static int vgic_its_restore_tables_v0(struct vgic_its *its);
static int vgic_its_commit_v0(struct vgic_its *its);
/* /*
* Creates a new (reference to a) struct vgic_irq for a given LPI. * Creates a new (reference to a) struct vgic_irq for a given LPI.
* If this LPI is already mapped on another ITS, we increase its refcount * If this LPI is already mapped on another ITS, we increase its refcount
@ -123,6 +127,50 @@ struct its_ite {
u32 event_id; u32 event_id;
}; };
/**
* struct vgic_its_abi - ITS abi ops and settings
* @cte_esz: collection table entry size
* @dte_esz: device table entry size
* @ite_esz: interrupt translation table entry size
* @save tables: save the ITS tables into guest RAM
* @restore_tables: restore the ITS internal structs from tables
* stored in guest RAM
* @commit: initialize the registers which expose the ABI settings,
* especially the entry sizes
*/
struct vgic_its_abi {
int cte_esz;
int dte_esz;
int ite_esz;
int (*save_tables)(struct vgic_its *its);
int (*restore_tables)(struct vgic_its *its);
int (*commit)(struct vgic_its *its);
};
static const struct vgic_its_abi its_table_abi_versions[] = {
[0] = {.cte_esz = 8, .dte_esz = 8, .ite_esz = 8,
.save_tables = vgic_its_save_tables_v0,
.restore_tables = vgic_its_restore_tables_v0,
.commit = vgic_its_commit_v0,
},
};
#define NR_ITS_ABIS ARRAY_SIZE(its_table_abi_versions)
inline const struct vgic_its_abi *vgic_its_get_abi(struct vgic_its *its)
{
return &its_table_abi_versions[its->abi_rev];
}
int vgic_its_set_abi(struct vgic_its *its, int rev)
{
const struct vgic_its_abi *abi;
its->abi_rev = rev;
abi = vgic_its_get_abi(its);
return abi->commit(its);
}
/* /*
* Find and returns a device in the device table for an ITS. * Find and returns a device in the device table for an ITS.
* Must be called with the its_lock mutex held. * Must be called with the its_lock mutex held.
@ -364,6 +412,7 @@ static unsigned long vgic_mmio_read_its_typer(struct kvm *kvm,
struct vgic_its *its, struct vgic_its *its,
gpa_t addr, unsigned int len) gpa_t addr, unsigned int len)
{ {
const struct vgic_its_abi *abi = vgic_its_get_abi(its);
u64 reg = GITS_TYPER_PLPIS; u64 reg = GITS_TYPER_PLPIS;
/* /*
@ -376,6 +425,7 @@ static unsigned long vgic_mmio_read_its_typer(struct kvm *kvm,
*/ */
reg |= 0x0f << GITS_TYPER_DEVBITS_SHIFT; reg |= 0x0f << GITS_TYPER_DEVBITS_SHIFT;
reg |= 0x0f << GITS_TYPER_IDBITS_SHIFT; reg |= 0x0f << GITS_TYPER_IDBITS_SHIFT;
reg |= GIC_ENCODE_SZ(abi->ite_esz, 4) << GITS_TYPER_ITT_ENTRY_SIZE_SHIFT;
return extract_bytes(reg, addr & 7, len); return extract_bytes(reg, addr & 7, len);
} }
@ -1268,6 +1318,7 @@ static void vgic_mmio_write_its_baser(struct kvm *kvm,
gpa_t addr, unsigned int len, gpa_t addr, unsigned int len,
unsigned long val) unsigned long val)
{ {
const struct vgic_its_abi *abi = vgic_its_get_abi(its);
u64 entry_size, device_type; u64 entry_size, device_type;
u64 reg, *regptr, clearbits = 0; u64 reg, *regptr, clearbits = 0;
@ -1278,12 +1329,12 @@ static void vgic_mmio_write_its_baser(struct kvm *kvm,
switch (BASER_INDEX(addr)) { switch (BASER_INDEX(addr)) {
case 0: case 0:
regptr = &its->baser_device_table; regptr = &its->baser_device_table;
entry_size = 8; entry_size = abi->dte_esz;
device_type = GITS_BASER_TYPE_DEVICE; device_type = GITS_BASER_TYPE_DEVICE;
break; break;
case 1: case 1:
regptr = &its->baser_coll_table; regptr = &its->baser_coll_table;
entry_size = 8; entry_size = abi->cte_esz;
device_type = GITS_BASER_TYPE_COLLECTION; device_type = GITS_BASER_TYPE_COLLECTION;
clearbits = GITS_BASER_INDIRECT; clearbits = GITS_BASER_INDIRECT;
break; break;
@ -1425,7 +1476,6 @@ static int vgic_register_its_iodev(struct kvm *kvm, struct vgic_its *its)
(GIC_BASER_CACHEABILITY(GITS_BASER, INNER, RaWb) | \ (GIC_BASER_CACHEABILITY(GITS_BASER, INNER, RaWb) | \
GIC_BASER_CACHEABILITY(GITS_BASER, OUTER, SameAsInner) | \ GIC_BASER_CACHEABILITY(GITS_BASER, OUTER, SameAsInner) | \
GIC_BASER_SHAREABILITY(GITS_BASER, InnerShareable) | \ GIC_BASER_SHAREABILITY(GITS_BASER, InnerShareable) | \
((8ULL - 1) << GITS_BASER_ENTRY_SIZE_SHIFT) | \
GITS_BASER_PAGE_SIZE_64K) GITS_BASER_PAGE_SIZE_64K)
#define INITIAL_PROPBASER_VALUE \ #define INITIAL_PROPBASER_VALUE \
@ -1465,7 +1515,7 @@ static int vgic_its_create(struct kvm_device *dev, u32 type)
dev->private = its; dev->private = its;
return 0; return vgic_its_set_abi(its, NR_ITS_ABIS - 1);
} }
static void vgic_its_destroy(struct kvm_device *kvm_dev) static void vgic_its_destroy(struct kvm_device *kvm_dev)
@ -1592,6 +1642,41 @@ int vgic_its_attr_regs_access(struct kvm_device *dev,
return ret; return ret;
} }
/**
* vgic_its_save_tables_v0 - Save the ITS tables into guest ARM
* according to v0 ABI
*/
static int vgic_its_save_tables_v0(struct vgic_its *its)
{
return -ENXIO;
}
/**
* vgic_its_restore_tables_v0 - Restore the ITS tables from guest RAM
* to internal data structs according to V0 ABI
*
*/
static int vgic_its_restore_tables_v0(struct vgic_its *its)
{
return -ENXIO;
}
static int vgic_its_commit_v0(struct vgic_its *its)
{
const struct vgic_its_abi *abi;
abi = vgic_its_get_abi(its);
its->baser_coll_table &= ~GITS_BASER_ENTRY_SIZE_MASK;
its->baser_device_table &= ~GITS_BASER_ENTRY_SIZE_MASK;
its->baser_coll_table |= (GIC_ENCODE_SZ(abi->cte_esz, 5)
<< GITS_BASER_ENTRY_SIZE_SHIFT);
its->baser_device_table |= (GIC_ENCODE_SZ(abi->dte_esz, 5)
<< GITS_BASER_ENTRY_SIZE_SHIFT);
return 0;
}
static int vgic_its_has_attr(struct kvm_device *dev, static int vgic_its_has_attr(struct kvm_device *dev,
struct kvm_device_attr *attr) struct kvm_device_attr *attr)
{ {