diff options
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/irqchip/irq-gic-v3-its.c | 25 |
1 files changed, 21 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); |
