This patch supports ITS in hardware domain, supports ITS in Xen
when booting with ACPI.
Signed-off-by: Manish Jaggi <mjaggi@xxxxxxxxxx>
---
Changes since v1:
- Moved its specific code to gic-v3-its.c
- fixed macros
xen/arch/arm/domain_build.c | 6 ++--
xen/arch/arm/gic-v3-its.c | 75 +++++++++++++++++++++++++++++++++++++++-
xen/arch/arm/gic-v3.c | 10 ++++--
xen/include/asm-arm/gic_v3_its.h | 6 ++++
4 files changed, 91 insertions(+), 6 deletions(-)
diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 3abacc0..d6d6c94 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -20,7 +20,7 @@
#include <asm/psci.h>
#include <asm/setup.h>
#include <asm/cpufeature.h>
-
+#include <asm-arm/gic_v3_its.h>
#include <asm/gic.h>
#include <xen/irq.h>
#include <xen/grant_table.h>
@@ -1804,7 +1804,9 @@ static int estimate_acpi_efi_size(struct domain *d, struct kernel_info *kinfo)
madt_size = sizeof(struct acpi_table_madt)
+ sizeof(struct acpi_madt_generic_interrupt) * d->max_vcpus
- + sizeof(struct acpi_madt_generic_distributor);
+ + sizeof(struct acpi_madt_generic_distributor)
+ + gicv3_its_madt_generic_translator_size();
+
if ( d->arch.vgic.version == GIC_V3 )
madt_size += sizeof(struct acpi_madt_generic_redistributor)
* d->arch.vgic.nr_regions;
diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c
index 1fb06ca..937b970 100644
--- a/xen/arch/arm/gic-v3-its.c
+++ b/xen/arch/arm/gic-v3-its.c
@@ -25,14 +25,18 @@
#include <xen/rbtree.h>
#include <xen/sched.h>
#include <xen/sizes.h>
+#include <xen/iocap.h>
#include <asm/gic.h>
#include <asm/gic_v3_defs.h>
#include <asm/gic_v3_its.h>
#include <asm/io.h>
#include <asm/page.h>
+#include <xen/acpi.h>
+#include <acpi/actables.h>
+#include <xen/pfn.h>
#define ITS_CMD_QUEUE_SZ SZ_1M
-
+#define ACPI_GICV3_ITS_MEM_SIZE (SZ_64K)
/*
* No lock here, as this list gets only populated upon boot while scanning
* firmware tables for all host ITSes, and only gets iterated afterwards.
@@ -920,6 +924,55 @@ int gicv3_lpi_change_vcpu(struct domain *d, paddr_t vdoorbell,
return 0;
}
+int gicv3_its_deny_access(const struct domain *d)
+{
+ int rc = 0;
+ unsigned long mfn, nr;
+ const struct host_its *its_data;
+
+ list_for_each_entry(its_data, &host_its_list, entry)
+ {
+ mfn = paddr_to_pfn(its_data->addr);
+ nr = PFN_UP(ACPI_GICV3_ITS_MEM_SIZE);
+ rc = iomem_deny_access(d, mfn, mfn + nr);
+ if ( rc )
+ goto end;
+ }
+end:
+ return rc;
+}
+
+u32 gicv3_its_madt_generic_translator_size(void)
+{
+ const struct host_its *its_data;
+ u32 size = 0;
+
+ list_for_each_entry(its_data, &host_its_list, entry)
+ {
+ size += sizeof(struct acpi_madt_generic_translator);
+ }
+ return size;
+}
+
+u32 gicv3_its_make_hwdom_madt(u8 *base_ptr, u32 offset)
+{
+ struct acpi_madt_generic_translator *gic_its;
+ const struct host_its *its_data;
+ u32 table_len = offset, size;
+
+ /* Update GIC ITS information in hardware domain's MADT */
+ list_for_each_entry(its_data, &host_its_list, entry)
+ {
+ size = sizeof(struct acpi_madt_generic_translator);
+ gic_its = (struct acpi_madt_generic_translator *)(base_ptr + table_len);
+ gic_its->header.type = ACPI_MADT_TYPE_GENERIC_TRANSLATOR;
+ gic_its->header.length = size;
+ gic_its->base_address = its_data->addr;
+ table_len += size;
+ }
+ return table_len;
+}
+
/*
* Create the respective guest DT nodes from a list of host ITSes.
* This copies the reg property, so the guest sees the ITS at the same address
@@ -992,6 +1045,26 @@ int gicv3_its_make_hwdom_dt_nodes(const struct domain *d,
return res;
}
+int gicv3_its_acpi_init(struct acpi_subtable_header *header, const unsigned long end)
+{
+ struct acpi_madt_generic_translator *its_entry;
+ struct host_its *its_data;
+
+ its_data = xzalloc(struct host_its);
+ if (!its_data)
+ return -1;
+
+ its_entry = (struct acpi_madt_generic_translator *)header;
+ its_data->addr = its_entry->base_address;
+ its_data->size = ACPI_GICV3_ITS_MEM_SIZE;
+
+ spin_lock_init(&its_data->cmd_lock);
+
+ printk("GICv3: Found ITS @0x%lx\n", its_data->addr);
+
+ list_add_tail(&its_data->entry, &host_its_list);
+ return 0;
+}
/* Scan the DT for any ITS nodes and create a list of host ITSes out of it. */
void gicv3_its_dt_init(const struct dt_device_node *node)
{
diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c
index c927306..f0f6d12 100644
--- a/xen/arch/arm/gic-v3.c
+++ b/xen/arch/arm/gic-v3.c
@@ -1333,9 +1333,8 @@ static int gicv3_iomem_deny_access(const struct domain *d)
return iomem_deny_access(d, mfn, mfn + nr);
}
- return 0;
+ return gicv3_its_deny_access(d);
}
-
#ifdef CONFIG_ACPI
static void __init
gic_acpi_add_rdist_region(paddr_t base, paddr_t size, bool single_rdist)
@@ -1374,6 +1373,7 @@ static int gicv3_make_hwdom_madt(const struct domain *d, u32 offset)
for ( i = 0; i < d->max_vcpus; i++ )
{
gicc = (struct acpi_madt_generic_interrupt *)(base_ptr + table_len);
+
ACPI_MEMCPY(gicc, host_gicc, size);
gicc->cpu_interface_number = i;
gicc->uid = i;
@@ -1399,7 +1399,7 @@ static int gicv3_make_hwdom_madt(const struct domain *d, u32 offset)
gicr->length = d->arch.vgic.rdist_regions[i].size;
table_len += size;
}
-
+ table_len = gicv3_its_make_hwdom_madt(base_ptr, table_len);
return table_len;
}
@@ -1567,6 +1567,9 @@ static void __init gicv3_acpi_init(void)
gicv3.rdist_stride = 0;
+ acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_TRANSLATOR,
+ gicv3_its_acpi_init, 0);
+
/*
* In ACPI, 0 is considered as the invalid address. However the rest
* of the initialization rely on the invalid address to be
@@ -1585,6 +1588,7 @@ static void __init gicv3_acpi_init(void)
else
vsize = GUEST_GICC_SIZE;
+
}
#else
static void __init gicv3_acpi_init(void) { }
diff --git a/xen/include/asm-arm/gic_v3_its.h b/xen/include/asm-arm/gic_v3_its.h
index d2a3e53..b72aec2 100644
--- a/xen/include/asm-arm/gic_v3_its.h
+++ b/xen/include/asm-arm/gic_v3_its.h
@@ -105,6 +105,7 @@
#include <xen/device_tree.h>
#include <xen/rbtree.h>
+#include <xen/acpi.h>
#define HOST_ITS_FLUSH_CMD_QUEUE (1U << 0)
#define HOST_ITS_USES_PTA (1U << 1)
@@ -134,6 +135,7 @@ extern struct list_head host_its_list;
/* Parse the host DT and pick up all host ITSes. */
void gicv3_its_dt_init(const struct dt_device_node *node);
+int gicv3_its_acpi_init(struct acpi_subtable_header *header, const unsigned long end);
bool gicv3_its_host_has_its(void);
@@ -167,6 +169,10 @@ int gicv3_its_make_hwdom_dt_nodes(const struct domain *d,
const struct dt_device_node *gic,
void *fdt);
+u32 gicv3_its_make_hwdom_madt(u8 *base_ptr, u32 offset);
+u32 gicv3_its_madt_generic_translator_size(void);
+/* Deny iomem access for its */
+int gicv3_its_deny_access(const struct domain *d);
/*
* Map a device on the host by allocating an ITT on the host (ITS).
* "nr_event" specifies how many events (interrupts) this device will need.
--
2.7.4
|