Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f54b97ed authored by Marc Zyngier's avatar Marc Zyngier Committed by Jason Cooper
Browse files

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: default avatarChen Baozi <chenbaozi@kylinos.com.cn>
Acked-by: default avatarChen Baozi <chenbaozi@kylinos.com.cn>
Signed-off-by: default avatarMarc Zyngier <marc.zyngier@arm.com>
Link: https://lkml.kernel.org/r/1425659870-11832-3-git-send-email-marc.zyngier@arm.com


Signed-off-by: default avatarJason Cooper <jason@lakedaemon.net>
parent 16acae72
Loading
Loading
Loading
Loading
+21 −4
Original line number Original line Diff line number Diff line
@@ -806,14 +806,31 @@ static int its_alloc_tables(struct its_node *its)
		u64 val = readq_relaxed(its->base + GITS_BASER + i * 8);
		u64 val = readq_relaxed(its->base + GITS_BASER + i * 8);
		u64 type = GITS_BASER_TYPE(val);
		u64 type = GITS_BASER_TYPE(val);
		u64 entry_size = GITS_BASER_ENTRY_SIZE(val);
		u64 entry_size = GITS_BASER_ENTRY_SIZE(val);
		int order = 0;
		int alloc_size;
		u64 tmp;
		u64 tmp;
		void *base;
		void *base;


		if (type == GITS_BASER_TYPE_NONE)
		if (type == GITS_BASER_TYPE_NONE)
			continue;
			continue;


		/* We're lazy and only allocate a single page for now */
		/*
		base = (void *)get_zeroed_page(GFP_KERNEL);
		 * Allocate as many entries as required to fit the
		 * range of device IDs that the ITS can grok... The ID
		 * space being incredibly sparse, this results in a
		 * massive waste of memory.
		 *
		 * For other tables, only allocate a single page.
		 */
		if (type == GITS_BASER_TYPE_DEVICE) {
			u64 typer = readq_relaxed(its->base + GITS_TYPER);
			u32 ids = GITS_TYPER_DEVBITS(typer);

			order = get_order((1UL << ids) * entry_size);
		}

		alloc_size = (1 << order) * PAGE_SIZE;
		base = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, order);
		if (!base) {
		if (!base) {
			err = -ENOMEM;
			err = -ENOMEM;
			goto out_free;
			goto out_free;
@@ -841,7 +858,7 @@ retry_baser:
			break;
			break;
		}
		}


		val |= (PAGE_SIZE / psz) - 1;
		val |= (alloc_size / psz) - 1;


		writeq_relaxed(val, its->base + GITS_BASER + i * 8);
		writeq_relaxed(val, its->base + GITS_BASER + i * 8);
		tmp = readq_relaxed(its->base + GITS_BASER + i * 8);
		tmp = readq_relaxed(its->base + GITS_BASER + i * 8);
@@ -882,7 +899,7 @@ retry_baser:
		}
		}


		pr_info("ITS: allocated %d %s @%lx (psz %dK, shr %d)\n",
		pr_info("ITS: allocated %d %s @%lx (psz %dK, shr %d)\n",
			(int)(PAGE_SIZE / entry_size),
			(int)(alloc_size / entry_size),
			its_base_type_string[type],
			its_base_type_string[type],
			(unsigned long)virt_to_phys(base),
			(unsigned long)virt_to_phys(base),
			psz / SZ_1K, (int)shr >> GITS_BASER_SHAREABILITY_SHIFT);
			psz / SZ_1K, (int)shr >> GITS_BASER_SHAREABILITY_SHIFT);
+2 −0
Original line number Original line Diff line number Diff line
@@ -166,6 +166,8 @@


#define GITS_TRANSLATER			0x10040
#define GITS_TRANSLATER			0x10040


#define GITS_TYPER_DEVBITS_SHIFT	13
#define GITS_TYPER_DEVBITS(r)		((((r) >> GITS_TYPER_DEVBITS_SHIFT) & 0x1f) + 1)
#define GITS_TYPER_PTA			(1UL << 19)
#define GITS_TYPER_PTA			(1UL << 19)


#define GITS_CBASER_VALID		(1UL << 63)
#define GITS_CBASER_VALID		(1UL << 63)