|
@@ -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 @@ out:
|
|
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)
|
|
{
|
|
{
|