From: Sunnanyong sunnanyong@huawei.com
If we want to support S4 (suspend to Disk), it is necessary to guarantee that the ITS tables are at the same address in the booting kernel and the resumed kernel. That covers all the ITS tables and as well as the RDs'.
To support this, allocting the itt memory from memory pool intead.
Signed-off-by: Sunnanyong sunnanyong@huawei.com --- drivers/irqchip/irq-gic-v3-its.c | 72 ++++++++++++++++++++++++++++++-- 1 file changed, 69 insertions(+), 3 deletions(-)
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 860f3ef2969e..9de585fe74fb 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -189,6 +189,14 @@ static DEFINE_IDA(its_vpeid_ida); #define gic_data_rdist_rd_base() (gic_data_rdist()->rd_base) #define gic_data_rdist_vlpi_base() (gic_data_rdist_rd_base() + SZ_128K)
+static void *its_mem_pool_alloc(int dev_id); +#define ITS_MEM_POOL_SIZE (SZ_4M) +#define ITS_MEM_POOL_MAX (16) +#define GITS_OTHER_OFFSET 0x20000 +#define GITS_OTHER_REG_SIZE 0x100 +#define GITS_FUNC_REG_OFFSET 0x80 +static void *its_mem_pool[ITS_MEM_POOL_MAX] = {0}; + static u16 get_its_list(struct its_vm *vm) { struct its_node *its; @@ -2436,7 +2444,11 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id, nr_ites = max(2, nvecs); sz = nr_ites * its->ite_size; sz = max(sz, ITS_ITT_ALIGN) + ITS_ITT_ALIGN - 1; - itt = kzalloc_node(sz, GFP_KERNEL, its->numa_node); + + itt = its_mem_pool_alloc(dev_id); + if (!itt) + itt = kzalloc_node(sz, GFP_KERNEL, its->numa_node); + if (alloc_lpis) { lpi_map = its_lpi_alloc(nvecs, &lpi_base, &nr_lpis); if (lpi_map) @@ -2450,7 +2462,6 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
if (!dev || !itt || !col_map || (!lpi_map && alloc_lpis)) { kfree(dev); - kfree(itt); kfree(lpi_map); kfree(col_map); return NULL; @@ -2486,7 +2497,6 @@ static void its_free_device(struct its_device *its_dev) raw_spin_lock_irqsave(&its_dev->its->lock, flags); list_del(&its_dev->entry); raw_spin_unlock_irqrestore(&its_dev->its->lock, flags); - kfree(its_dev->itt); kfree(its_dev); }
@@ -3798,11 +3808,41 @@ static int redist_disable_lpis(void) return 0; }
+static void its_cpu_clear_cache(void) +{ + struct its_node *its; + u64 val = 0; + void __iomem *func_base; + + raw_spin_lock(&its_lock); + + list_for_each_entry(its, &its_nodes, entry) { + func_base = ioremap(its->phys_base + GITS_OTHER_OFFSET, + GITS_OTHER_REG_SIZE); + if (!func_base) { + pr_err("ITS@%p : Unable to map ITS OTHER registers\n", + (void *)(its->phys_base + GITS_OTHER_OFFSET)); + raw_spin_unlock(&its_lock); + return; + } + + val = readl_relaxed(func_base + GITS_FUNC_REG_OFFSET); + val = val | (0x7 << 16); + writel_relaxed(val, func_base + GITS_FUNC_REG_OFFSET); + dsb(sy); + iounmap(func_base); + } + + raw_spin_unlock(&its_lock); +} + + int its_cpu_init(void) { if (!list_empty(&its_nodes)) { int ret;
+ its_cpu_clear_cache(); ret = redist_disable_lpis(); if (ret) return ret; @@ -4001,6 +4041,7 @@ int __init its_init(struct fwnode_handle *handle, struct rdists *rdists, struct its_node *its; bool has_v4 = false; int err; + int i;
its_parent = parent_domain; of_node = to_of_node(handle); @@ -4014,6 +4055,16 @@ int __init its_init(struct fwnode_handle *handle, struct rdists *rdists, return -ENXIO; }
+ for (i = 0; i < ITS_MEM_POOL_MAX; i++) { + if (!its_mem_pool[i]) { + its_mem_pool[i] = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, + get_order(ITS_MEM_POOL_SIZE)); + if (!its_mem_pool[i]) + pr_err("err:[its mem[%d]] has no memory\n", i); + } + } + + gic_rdists = rdists;
err = allocate_lpi_tables(); @@ -4035,3 +4086,18 @@ int __init its_init(struct fwnode_handle *handle, struct rdists *rdists,
return 0; } + +void *its_mem_pool_alloc(int dev_id) +{ + int pool_num = dev_id / (ITS_MEM_POOL_SIZE / SZ_512); + int idx = dev_id % (ITS_MEM_POOL_SIZE / SZ_512); + void *addr = NULL; + + if (pool_num >= ITS_MEM_POOL_MAX || !its_mem_pool[pool_num]) { + pr_err("[its mem[%d]] alloc error\n", pool_num); + return NULL; + } + + addr = its_mem_pool[pool_num] + idx * SZ_512; + return addr; +}