@@ -20,10 +20,13 @@
#include <xen/lib.h>
#include <xen/mm.h>
+#include <xen/sizes.h>
#include <asm/gic_v3_defs.h>
#include <asm/gic_v3_its.h>
#include <asm/io.h>
+#define ITS_CMD_QUEUE_SZ SZ_1M
+
/*
* No lock here, as this list gets only populated upon boot while scanning
* firmware tables for all host ITSes, and only gets iterated afterwards.
@@ -60,6 +63,51 @@ static uint64_t encode_baser_phys_addr(paddr_t addr, unsigned int page_bits)
return ret | ((addr & GENMASK_ULL(51, 48)) >> (48 - 12));
}
+static void *its_map_cbaser(struct host_its *its)
+{
+ void __iomem *cbasereg = its->its_base + GITS_CBASER;
+ uint64_t reg;
+ void *buffer;
+
+ reg = GIC_BASER_InnerShareable << GITS_BASER_SHAREABILITY_SHIFT;
+ reg |= GIC_BASER_CACHE_SameAsInner << GITS_BASER_OUTER_CACHEABILITY_SHIFT;
+ reg |= GIC_BASER_CACHE_RaWaWb << GITS_BASER_INNER_CACHEABILITY_SHIFT;
+
+ buffer = _xzalloc(ITS_CMD_QUEUE_SZ, SZ_64K);
+ if ( !buffer )
+ return NULL;
+
+ if ( virt_to_maddr(buffer) & ~GENMASK_ULL(51, 12) )
+ {
+ xfree(buffer);
+ return NULL;
+ }
+
+ reg |= GITS_VALID_BIT | virt_to_maddr(buffer);
+ reg |= ((ITS_CMD_QUEUE_SZ / SZ_4K) - 1) & GITS_CBASER_SIZE_MASK;
+ writeq_relaxed(reg, cbasereg);
+ reg = readq_relaxed(cbasereg);
+
+ /* If the ITS dropped shareability, drop cacheability as well. */
+ if ( (reg & GITS_BASER_SHAREABILITY_MASK) == 0 )
+ {
+ reg &= ~GITS_BASER_INNER_CACHEABILITY_MASK;
+ writeq_relaxed(reg, cbasereg);
+ }
+
+ /*
+ * If the command queue memory is mapped as uncached, we need to flush
+ * it on every access.
+ */
+ if ( !(reg & GITS_BASER_INNER_CACHEABILITY_MASK) )
+ {
+ its->flags |= HOST_ITS_FLUSH_CMD_QUEUE;
+ printk(XENLOG_WARNING "using non-cacheable ITS command queue\n");
+ }
+
+ return buffer;
+}
+
/* The ITS BASE registers work with page sizes of 4K, 16K or 64K. */
#define BASER_PAGE_BITS(sz) ((sz) * 2 + 12)
@@ -180,6 +228,11 @@ static int gicv3_its_init_single_its(struct host_its *hw_its)
}
}
+ hw_its->cmd_buf = its_map_cbaser(hw_its);
+ if ( !hw_its->cmd_buf )
+ return -ENOMEM;
+ writeq_relaxed(0, hw_its->its_base + GITS_CWRITER);
+
return 0;
}
@@ -84,8 +84,12 @@
#define GITS_BASER_OUTER_CACHEABILITY_MASK (0x7ULL << GITS_BASER_OUTER_CACHEABILITY_SHIFT)
#define GITS_BASER_INNER_CACHEABILITY_MASK (0x7ULL << GITS_BASER_INNER_CACHEABILITY_SHIFT)
+#define GITS_CBASER_SIZE_MASK 0xff
+
#include <xen/device_tree.h>
+#define HOST_ITS_FLUSH_CMD_QUEUE (1U << 0)
+
/* data structure for each hardware ITS */
struct host_its {
struct list_head entry;
@@ -96,6 +100,8 @@ struct host_its {
unsigned int devid_bits;
unsigned int evid_bits;
unsigned int itte_size;
+ void *cmd_buf;
+ unsigned int flags;
};