irqchip/gicv3-its: Use NUMA aware memory allocation for ITS tables
authorShanker Donthineni <shankerd@codeaurora.org>
Mon, 14 Jan 2019 09:50:19 +0000 (09:50 +0000)
committerMarc Zyngier <marc.zyngier@arm.com>
Thu, 21 Feb 2019 10:32:29 +0000 (10:32 +0000)
The NUMA node information is visible to ITS driver but not being used
other than handling hardware errata. ITS/GICR hardware accesses to the
local NUMA node is usually quicker than the remote NUMA node. How slow
the remote NUMA accesses are depends on the implementation details.

This patch allocates memory for ITS management tables and command
queue from the corresponding NUMA node using the appropriate NUMA
aware functions. This change improves the performance of the ITS
tables read latency on systems where it has more than one ITS block,
and with the slower inter node accesses.

Apache Web server benchmarking using ab tool on a HiSilicon D06
board with multiple numa mem nodes shows Time per request and
Transfer rate improvements of ~3.6% with this patch.

Signed-off-by: Shanker Donthineni <shankerd@codeaurora.org>
Signed-off-by: Hanjun Guo <guohanjun@huawei.com>
Signed-off-by: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>
Reviewed-by: Ganapatrao Kulkarni <gkulkarni@marvell.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
drivers/irqchip/irq-gic-v3-its.c

index 9f529a6..fb71571 100644 (file)
@@ -1737,6 +1737,7 @@ static int its_setup_baser(struct its_node *its, struct its_baser *baser,
        u64 type = GITS_BASER_TYPE(val);
        u64 baser_phys, tmp;
        u32 alloc_pages;
+       struct page *page;
        void *base;
 
 retry_alloc_baser:
@@ -1749,10 +1750,11 @@ retry_alloc_baser:
                order = get_order(GITS_BASER_PAGES_MAX * psz);
        }
 
-       base = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, order);
-       if (!base)
+       page = alloc_pages_node(its->numa_node, GFP_KERNEL | __GFP_ZERO, order);
+       if (!page)
                return -ENOMEM;
 
+       base = (void *)page_address(page);
        baser_phys = virt_to_phys(base);
 
        /* Check if the physical address of the memory is above 48bits */
@@ -2238,7 +2240,8 @@ static struct its_baser *its_get_baser(struct its_node *its, u32 type)
        return NULL;
 }
 
-static bool its_alloc_table_entry(struct its_baser *baser, u32 id)
+static bool its_alloc_table_entry(struct its_node *its,
+                                 struct its_baser *baser, u32 id)
 {
        struct page *page;
        u32 esz, idx;
@@ -2258,7 +2261,8 @@ static bool its_alloc_table_entry(struct its_baser *baser, u32 id)
 
        /* Allocate memory for 2nd level table */
        if (!table[idx]) {
-               page = alloc_pages(GFP_KERNEL | __GFP_ZERO, get_order(baser->psz));
+               page = alloc_pages_node(its->numa_node, GFP_KERNEL | __GFP_ZERO,
+                                       get_order(baser->psz));
                if (!page)
                        return false;
 
@@ -2289,7 +2293,7 @@ static bool its_alloc_device_table(struct its_node *its, u32 dev_id)
        if (!baser)
                return (ilog2(dev_id) < its->device_ids);
 
-       return its_alloc_table_entry(baser, dev_id);
+       return its_alloc_table_entry(its, baser, dev_id);
 }
 
 static bool its_alloc_vpe_table(u32 vpe_id)
@@ -2313,7 +2317,7 @@ static bool its_alloc_vpe_table(u32 vpe_id)
                if (!baser)
                        return false;
 
-               if (!its_alloc_table_entry(baser, vpe_id))
+               if (!its_alloc_table_entry(its, baser, vpe_id))
                        return false;
        }
 
@@ -2347,7 +2351,7 @@ 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(sz, GFP_KERNEL);
+       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)
@@ -3488,6 +3492,7 @@ static int __init its_probe_one(struct resource *res,
        void __iomem *its_base;
        u32 val, ctlr;
        u64 baser, tmp, typer;
+       struct page *page;
        int err;
 
        its_base = ioremap(res->start, resource_size(res));
@@ -3543,12 +3548,13 @@ static int __init its_probe_one(struct resource *res,
 
        its->numa_node = numa_node;
 
-       its->cmd_base = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
-                                               get_order(ITS_CMD_QUEUE_SZ));
-       if (!its->cmd_base) {
+       page = alloc_pages_node(its->numa_node, GFP_KERNEL | __GFP_ZERO,
+                               get_order(ITS_CMD_QUEUE_SZ));
+       if (!page) {
                err = -ENOMEM;
                goto out_free_its;
        }
+       its->cmd_base = (void *)page_address(page);
        its->cmd_write = its->cmd_base;
        its->fwnode_handle = handle;
        its->get_msi_base = its_irq_get_msi_base;