aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarc Zyngier <marc.zyngier@arm.com>2015-03-06 11:37:41 -0500
committerJason Cooper <jason@lakedaemon.net>2015-03-08 00:32:52 -0500
commitf54b97ed0b17d3da5f98ba8188cd5646415a922d (patch)
tree4664ec806519ff6d594d547d8b31be5bc774fc0a
parent16acae729564ee0c3918342d8556cc42eeb29942 (diff)
irqchip: gicv3-its: Allocate enough memory for the full range of DeviceID
The ITS table allocator is only allocating a single page per table. This works fine for most things, but leads to silent lack of interrupt delivery if we end-up with a device that has an ID that is out of the range defined by a single page of memory. Even worse, depending on the page size, behaviour changes, which is not a very good experience. A solution is actually to allocate memory for the full range of ID that the ITS supports. A massive waste memory wise, but at least a safe bet. Tested on a Phytium SoC. Tested-by: Chen Baozi <chenbaozi@kylinos.com.cn> Acked-by: Chen Baozi <chenbaozi@kylinos.com.cn> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com> Link: https://lkml.kernel.org/r/1425659870-11832-3-git-send-email-marc.zyngier@arm.com Signed-off-by: Jason Cooper <jason@lakedaemon.net>
-rw-r--r--drivers/irqchip/irq-gic-v3-its.c25
-rw-r--r--include/linux/irqchip/arm-gic-v3.h2
2 files changed, 23 insertions, 4 deletions
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index c217ebcf7a48..733b32fda390 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -806,14 +806,31 @@ static int its_alloc_tables(struct its_node *its)
806 u64 val = readq_relaxed(its->base + GITS_BASER + i * 8); 806 u64 val = readq_relaxed(its->base + GITS_BASER + i * 8);
807 u64 type = GITS_BASER_TYPE(val); 807 u64 type = GITS_BASER_TYPE(val);
808 u64 entry_size = GITS_BASER_ENTRY_SIZE(val); 808 u64 entry_size = GITS_BASER_ENTRY_SIZE(val);
809 int order = 0;
810 int alloc_size;
809 u64 tmp; 811 u64 tmp;
810 void *base; 812 void *base;
811 813
812 if (type == GITS_BASER_TYPE_NONE) 814 if (type == GITS_BASER_TYPE_NONE)
813 continue; 815 continue;
814 816
815 /* We're lazy and only allocate a single page for now */ 817 /*
816 base = (void *)get_zeroed_page(GFP_KERNEL); 818 * Allocate as many entries as required to fit the
819 * range of device IDs that the ITS can grok... The ID
820 * space being incredibly sparse, this results in a
821 * massive waste of memory.
822 *
823 * For other tables, only allocate a single page.
824 */
825 if (type == GITS_BASER_TYPE_DEVICE) {
826 u64 typer = readq_relaxed(its->base + GITS_TYPER);
827 u32 ids = GITS_TYPER_DEVBITS(typer);
828
829 order = get_order((1UL << ids) * entry_size);
830 }
831
832 alloc_size = (1 << order) * PAGE_SIZE;
833 base = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, order);
817 if (!base) { 834 if (!base) {
818 err = -ENOMEM; 835 err = -ENOMEM;
819 goto out_free; 836 goto out_free;
@@ -841,7 +858,7 @@ retry_baser:
841 break; 858 break;
842 } 859 }
843 860
844 val |= (PAGE_SIZE / psz) - 1; 861 val |= (alloc_size / psz) - 1;
845 862
846 writeq_relaxed(val, its->base + GITS_BASER + i * 8); 863 writeq_relaxed(val, its->base + GITS_BASER + i * 8);
847 tmp = readq_relaxed(its->base + GITS_BASER + i * 8); 864 tmp = readq_relaxed(its->base + GITS_BASER + i * 8);
@@ -882,7 +899,7 @@ retry_baser:
882 } 899 }
883 900
884 pr_info("ITS: allocated %d %s @%lx (psz %dK, shr %d)\n", 901 pr_info("ITS: allocated %d %s @%lx (psz %dK, shr %d)\n",
885 (int)(PAGE_SIZE / entry_size), 902 (int)(alloc_size / entry_size),
886 its_base_type_string[type], 903 its_base_type_string[type],
887 (unsigned long)virt_to_phys(base), 904 (unsigned long)virt_to_phys(base),
888 psz / SZ_1K, (int)shr >> GITS_BASER_SHAREABILITY_SHIFT); 905 psz / SZ_1K, (int)shr >> GITS_BASER_SHAREABILITY_SHIFT);
diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
index 800544bc7bfd..cbdd440d486d 100644
--- a/include/linux/irqchip/arm-gic-v3.h
+++ b/include/linux/irqchip/arm-gic-v3.h
@@ -166,6 +166,8 @@
166 166
167#define GITS_TRANSLATER 0x10040 167#define GITS_TRANSLATER 0x10040
168 168
169#define GITS_TYPER_DEVBITS_SHIFT 13
170#define GITS_TYPER_DEVBITS(r) ((((r) >> GITS_TYPER_DEVBITS_SHIFT) & 0x1f) + 1)
169#define GITS_TYPER_PTA (1UL << 19) 171#define GITS_TYPER_PTA (1UL << 19)
170 172
171#define GITS_CBASER_VALID (1UL << 63) 173#define GITS_CBASER_VALID (1UL << 63)