Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 71afe470 authored by Eric Auger's avatar Eric Auger Committed by Christoffer Dall
Browse files

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: default avatarEric Auger <eric.auger@redhat.com>
Reviewed-by: default avatarChristoffer Dall <cdall@linaro.org>
parent 0979bfa6
Loading
Loading
Loading
Loading
+3 −0
Original line number Original line Diff line number Diff line
@@ -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;
+5 −0
Original line number Original line Diff line number Diff line
@@ -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)
+89 −4
Original line number Original line Diff line number Diff line
@@ -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)
{
{