xref: /kvm-unit-tests/lib/arm64/gic-v3-its.c (revision b4667f4ca26aea926a2ddecfcb5669e0e4e7cbf4)
1ba74b106SEric Auger /*
2ba74b106SEric Auger  * Copyright (C) 2020, Red Hat Inc, Eric Auger <eric.auger@redhat.com>
3ba74b106SEric Auger  *
4ba74b106SEric Auger  * This work is licensed under the terms of the GNU LGPL, version 2.
5ba74b106SEric Auger  */
6ba74b106SEric Auger #include <asm/gic.h>
7ba74b106SEric Auger #include <alloc_page.h>
8ba74b106SEric Auger 
its_parse_typer(void)9ba74b106SEric Auger void its_parse_typer(void)
10ba74b106SEric Auger {
11ba74b106SEric Auger 	u64 typer = readq(gicv3_its_base() + GITS_TYPER);
12ba74b106SEric Auger 	struct its_typer *t = &its_data.typer;
13ba74b106SEric Auger 
14ba74b106SEric Auger 	t->ite_size = ((typer & GITS_TYPER_ITT_ENTRY_SIZE) >> GITS_TYPER_ITT_ENTRY_SIZE_SHIFT) + 1;
15ba74b106SEric Auger 	t->pta = typer & GITS_TYPER_PTA;
16ba74b106SEric Auger 	t->eventid_bits = ((typer & GITS_TYPER_IDBITS) >> GITS_TYPER_IDBITS_SHIFT) + 1;
17ba74b106SEric Auger 	t->deviceid_bits = ((typer & GITS_TYPER_DEVBITS) >> GITS_TYPER_DEVBITS_SHIFT) + 1;
18ba74b106SEric Auger 
19ba74b106SEric Auger 	if (typer & GITS_TYPER_CIL)
20ba74b106SEric Auger 		t->collid_bits = ((typer & GITS_TYPER_CIDBITS) >> GITS_TYPER_CIDBITS_SHIFT) + 1;
21ba74b106SEric Auger 	else
22ba74b106SEric Auger 		t->collid_bits = 16;
23ba74b106SEric Auger 
24ba74b106SEric Auger 	t->virt_lpi = typer & GITS_TYPER_VLPIS;
25ba74b106SEric Auger 	t->phys_lpi = typer & GITS_TYPER_PLPIS;
26ba74b106SEric Auger }
27ba74b106SEric Auger 
its_baser_lookup(int type,struct its_baser * baser)28ba74b106SEric Auger int its_baser_lookup(int type, struct its_baser *baser)
29ba74b106SEric Auger {
30ba74b106SEric Auger 	int i;
31ba74b106SEric Auger 
32ba74b106SEric Auger 	for (i = 0; i < GITS_BASER_NR_REGS; i++) {
33ba74b106SEric Auger 		void *reg_addr = gicv3_its_base() + GITS_BASER + i * 8;
34ba74b106SEric Auger 		u64 val = readq(reg_addr);
35ba74b106SEric Auger 
36ba74b106SEric Auger 		if (GITS_BASER_TYPE(val) == type) {
37ba74b106SEric Auger 			assert((val & GITS_BASER_PAGE_SIZE_MASK) == GITS_BASER_PAGE_SIZE_64K);
38ba74b106SEric Auger 			baser->esz = GITS_BASER_ENTRY_SIZE(val);
39ba74b106SEric Auger 			baser->indirect = val & GITS_BASER_INDIRECT;
40ba74b106SEric Auger 			baser->index = i;
41ba74b106SEric Auger 			return 0;
42ba74b106SEric Auger 		}
43ba74b106SEric Auger 	}
44ba74b106SEric Auger 	return -1;
45ba74b106SEric Auger }
46ba74b106SEric Auger 
47ba74b106SEric Auger /*
48ba74b106SEric Auger  * Allocate the BASER table (a single page of size @baser->psz)
49ba74b106SEric Auger  * and set the BASER valid
50ba74b106SEric Auger  */
its_baser_alloc_table(struct its_baser * baser,size_t size)51ba74b106SEric Auger static void its_baser_alloc_table(struct its_baser *baser, size_t size)
52ba74b106SEric Auger {
53ba74b106SEric Auger 	unsigned long order = get_order(size >> PAGE_SHIFT);
54ba74b106SEric Auger 	void *reg_addr = gicv3_its_base() + GITS_BASER + baser->index * 8;
55ba74b106SEric Auger 	u64 val = readq(reg_addr);
56ba74b106SEric Auger 
57ba74b106SEric Auger 	baser->table_addr = alloc_pages(order);
58ba74b106SEric Auger 
59ba74b106SEric Auger 	val |= virt_to_phys(baser->table_addr) | GITS_BASER_VALID;
60ba74b106SEric Auger 
61ba74b106SEric Auger 	writeq(val, reg_addr);
62ba74b106SEric Auger }
63ba74b106SEric Auger 
64ba74b106SEric Auger /*
65ba74b106SEric Auger  * init_cmd_queue - Allocate the command queue and initialize
66ba74b106SEric Auger  * CBASER, CWRITER
67ba74b106SEric Auger  */
its_cmd_queue_init(void)68ba74b106SEric Auger static void its_cmd_queue_init(void)
69ba74b106SEric Auger {
70ba74b106SEric Auger 	unsigned long order = get_order(SZ_64K >> PAGE_SHIFT);
71ba74b106SEric Auger 	u64 cbaser;
72ba74b106SEric Auger 
73ba74b106SEric Auger 	its_data.cmd_base = alloc_pages(order);
74ba74b106SEric Auger 
75ba74b106SEric Auger 	cbaser = virt_to_phys(its_data.cmd_base) | (SZ_64K / SZ_4K - 1) | GITS_CBASER_VALID;
76ba74b106SEric Auger 
77ba74b106SEric Auger 	writeq(cbaser, its_data.base + GITS_CBASER);
78ba74b106SEric Auger 
79ba74b106SEric Auger 	its_data.cmd_write = its_data.cmd_base;
80ba74b106SEric Auger 	writeq(0, its_data.base + GITS_CWRITER);
81ba74b106SEric Auger }
82ba74b106SEric Auger 
its_init(void)83ba74b106SEric Auger void its_init(void)
84ba74b106SEric Auger {
85ba74b106SEric Auger 	if (!its_data.base)
86ba74b106SEric Auger 		return;
87ba74b106SEric Auger 
88ba74b106SEric Auger 	its_parse_typer();
89ba74b106SEric Auger 
90ba74b106SEric Auger 	assert(!its_baser_lookup(GITS_BASER_TYPE_DEVICE, &its_data.device_baser));
91ba74b106SEric Auger 	assert(!its_baser_lookup(GITS_BASER_TYPE_COLLECTION, &its_data.coll_baser));
92ba74b106SEric Auger 
93ba74b106SEric Auger 	its_baser_alloc_table(&its_data.device_baser, SZ_64K);
94ba74b106SEric Auger 	its_baser_alloc_table(&its_data.coll_baser, SZ_64K);
95ba74b106SEric Auger 
96ba74b106SEric Auger 	its_cmd_queue_init();
97ba74b106SEric Auger }
98ba74b106SEric Auger 
9980374e12SEric Auger /* must be called after gicv3_enable_defaults */
its_enable_defaults(void)10080374e12SEric Auger void its_enable_defaults(void)
10180374e12SEric Auger {
10280374e12SEric Auger 	int cpu;
10380374e12SEric Auger 
10480374e12SEric Auger 	/* Allocate LPI config and pending tables */
10580374e12SEric Auger 	gicv3_lpi_alloc_tables();
10680374e12SEric Auger 
107*b4667f4cSAndrew Jones 	for_each_online_cpu(cpu)
10880374e12SEric Auger 		gicv3_lpi_rdist_enable(cpu);
10980374e12SEric Auger 
11080374e12SEric Auger 	writel(GITS_CTLR_ENABLE, its_data.base + GITS_CTLR);
11180374e12SEric Auger }
1120c87bc34SEric Auger 
its_create_device(u32 device_id,int nr_ites)1130c87bc34SEric Auger struct its_device *its_create_device(u32 device_id, int nr_ites)
1140c87bc34SEric Auger {
1150c87bc34SEric Auger 	struct its_device *new;
1160c87bc34SEric Auger 	unsigned long n;
1170c87bc34SEric Auger 
1180c87bc34SEric Auger 	assert(its_data.nr_devices < GITS_MAX_DEVICES);
1190c87bc34SEric Auger 
1200c87bc34SEric Auger 	new = &its_data.devices[its_data.nr_devices];
1210c87bc34SEric Auger 
1220c87bc34SEric Auger 	new->device_id = device_id;
1230c87bc34SEric Auger 	new->nr_ites = nr_ites;
1240c87bc34SEric Auger 
1250c87bc34SEric Auger 	n = (its_data.typer.ite_size * nr_ites) >> PAGE_SHIFT;
1260c87bc34SEric Auger 	new->itt = alloc_pages(get_order(n));
1270c87bc34SEric Auger 
1280c87bc34SEric Auger 	its_data.nr_devices++;
1290c87bc34SEric Auger 	return new;
1300c87bc34SEric Auger }
1310c87bc34SEric Auger 
its_create_collection(u16 col_id,u32 pe)1320c87bc34SEric Auger struct its_collection *its_create_collection(u16 col_id, u32 pe)
1330c87bc34SEric Auger {
1340c87bc34SEric Auger 	struct its_collection *new;
1350c87bc34SEric Auger 
1360c87bc34SEric Auger 	assert(its_data.nr_collections < GITS_MAX_COLLECTIONS);
1370c87bc34SEric Auger 
1380c87bc34SEric Auger 	new = &its_data.collections[its_data.nr_collections];
1390c87bc34SEric Auger 
1400c87bc34SEric Auger 	new->col_id = col_id;
1410c87bc34SEric Auger 
1420c87bc34SEric Auger 	if (its_data.typer.pta)
1430c87bc34SEric Auger 		new->target_address = (u64)gicv3_data.redist_base[pe];
1440c87bc34SEric Auger 	else
1450c87bc34SEric Auger 		new->target_address = pe << 16;
1460c87bc34SEric Auger 
1470c87bc34SEric Auger 	its_data.nr_collections++;
1480c87bc34SEric Auger 	return new;
1490c87bc34SEric Auger }
15064260a5fSEric Auger 
its_get_device(u32 id)15164260a5fSEric Auger struct its_device *its_get_device(u32 id)
15264260a5fSEric Auger {
15364260a5fSEric Auger 	int i;
15464260a5fSEric Auger 
15564260a5fSEric Auger 	for (i = 0; i < GITS_MAX_DEVICES; i++) {
15664260a5fSEric Auger 		if (its_data.devices[i].device_id == id)
15764260a5fSEric Auger 			return &its_data.devices[i];
15864260a5fSEric Auger 	}
15964260a5fSEric Auger 	assert(0);
16064260a5fSEric Auger }
16164260a5fSEric Auger 
its_get_collection(u32 id)16264260a5fSEric Auger struct its_collection *its_get_collection(u32 id)
16364260a5fSEric Auger {
16464260a5fSEric Auger 	int i;
16564260a5fSEric Auger 
16664260a5fSEric Auger 	for (i = 0; i < GITS_MAX_COLLECTIONS; i++) {
16764260a5fSEric Auger 		if (its_data.collections[i].col_id == id)
16864260a5fSEric Auger 			return &its_data.collections[i];
16964260a5fSEric Auger 	}
17064260a5fSEric Auger 	assert(0);
17164260a5fSEric Auger }
172