mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
ARM: GICv3 ITS: map ITS command buffer
Instead of directly manipulating the tables in memory, an ITS driver sends commands via a ring buffer in normal system memory to the ITS h/w to create or alter the LPI mappings. Allocate memory for that buffer and tell the ITS about it to be able to send ITS commands. Signed-off-by: Andre Przywara <andre.przywara@arm.com> Reviewed-by: Stefano Stabellini <sstabellini@kernel.org> Reviewed-by: Julien Grall <julien.grall@arm.com>
This commit is contained in:
1 parent
05238012b8
commit
8ed8d21373
2 files changed
+59
No files matched your search
@@ -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(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(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;
|
||||
}
|
||||
|
||||
|
||||
@@ -79,8 +79,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;
|
||||
@@ -91,6 +95,8 @@ struct host_its {
|
||||
unsigned int devid_bits;
|
||||
unsigned int evid_bits;
|
||||
unsigned int itte_size;
|
||||
void *cmd_buf;
|
||||
unsigned int flags;
|
||||
};
|
||||
|
||||
|
||||
|
||||