xref: /kvm-unit-tests/lib/arm64/gic-v3-its.c (revision ba74b1063d21003ff7de7a84af121af2d3663c1f)
1*ba74b106SEric Auger /*
2*ba74b106SEric Auger  * Copyright (C) 2020, Red Hat Inc, Eric Auger <eric.auger@redhat.com>
3*ba74b106SEric Auger  *
4*ba74b106SEric Auger  * This work is licensed under the terms of the GNU LGPL, version 2.
5*ba74b106SEric Auger  */
6*ba74b106SEric Auger #include <asm/gic.h>
7*ba74b106SEric Auger #include <alloc_page.h>
8*ba74b106SEric Auger 
9*ba74b106SEric Auger void its_parse_typer(void)
10*ba74b106SEric Auger {
11*ba74b106SEric Auger 	u64 typer = readq(gicv3_its_base() + GITS_TYPER);
12*ba74b106SEric Auger 	struct its_typer *t = &its_data.typer;
13*ba74b106SEric Auger 
14*ba74b106SEric Auger 	t->ite_size = ((typer & GITS_TYPER_ITT_ENTRY_SIZE) >> GITS_TYPER_ITT_ENTRY_SIZE_SHIFT) + 1;
15*ba74b106SEric Auger 	t->pta = typer & GITS_TYPER_PTA;
16*ba74b106SEric Auger 	t->eventid_bits = ((typer & GITS_TYPER_IDBITS) >> GITS_TYPER_IDBITS_SHIFT) + 1;
17*ba74b106SEric Auger 	t->deviceid_bits = ((typer & GITS_TYPER_DEVBITS) >> GITS_TYPER_DEVBITS_SHIFT) + 1;
18*ba74b106SEric Auger 
19*ba74b106SEric Auger 	if (typer & GITS_TYPER_CIL)
20*ba74b106SEric Auger 		t->collid_bits = ((typer & GITS_TYPER_CIDBITS) >> GITS_TYPER_CIDBITS_SHIFT) + 1;
21*ba74b106SEric Auger 	else
22*ba74b106SEric Auger 		t->collid_bits = 16;
23*ba74b106SEric Auger 
24*ba74b106SEric Auger 	t->virt_lpi = typer & GITS_TYPER_VLPIS;
25*ba74b106SEric Auger 	t->phys_lpi = typer & GITS_TYPER_PLPIS;
26*ba74b106SEric Auger }
27*ba74b106SEric Auger 
28*ba74b106SEric Auger int its_baser_lookup(int type, struct its_baser *baser)
29*ba74b106SEric Auger {
30*ba74b106SEric Auger 	int i;
31*ba74b106SEric Auger 
32*ba74b106SEric Auger 	for (i = 0; i < GITS_BASER_NR_REGS; i++) {
33*ba74b106SEric Auger 		void *reg_addr = gicv3_its_base() + GITS_BASER + i * 8;
34*ba74b106SEric Auger 		u64 val = readq(reg_addr);
35*ba74b106SEric Auger 
36*ba74b106SEric Auger 		if (GITS_BASER_TYPE(val) == type) {
37*ba74b106SEric Auger 			assert((val & GITS_BASER_PAGE_SIZE_MASK) == GITS_BASER_PAGE_SIZE_64K);
38*ba74b106SEric Auger 			baser->esz = GITS_BASER_ENTRY_SIZE(val);
39*ba74b106SEric Auger 			baser->indirect = val & GITS_BASER_INDIRECT;
40*ba74b106SEric Auger 			baser->index = i;
41*ba74b106SEric Auger 			return 0;
42*ba74b106SEric Auger 		}
43*ba74b106SEric Auger 	}
44*ba74b106SEric Auger 	return -1;
45*ba74b106SEric Auger }
46*ba74b106SEric Auger 
47*ba74b106SEric Auger /*
48*ba74b106SEric Auger  * Allocate the BASER table (a single page of size @baser->psz)
49*ba74b106SEric Auger  * and set the BASER valid
50*ba74b106SEric Auger  */
51*ba74b106SEric Auger static void its_baser_alloc_table(struct its_baser *baser, size_t size)
52*ba74b106SEric Auger {
53*ba74b106SEric Auger 	unsigned long order = get_order(size >> PAGE_SHIFT);
54*ba74b106SEric Auger 	void *reg_addr = gicv3_its_base() + GITS_BASER + baser->index * 8;
55*ba74b106SEric Auger 	u64 val = readq(reg_addr);
56*ba74b106SEric Auger 
57*ba74b106SEric Auger 	baser->table_addr = alloc_pages(order);
58*ba74b106SEric Auger 
59*ba74b106SEric Auger 	val |= virt_to_phys(baser->table_addr) | GITS_BASER_VALID;
60*ba74b106SEric Auger 
61*ba74b106SEric Auger 	writeq(val, reg_addr);
62*ba74b106SEric Auger }
63*ba74b106SEric Auger 
64*ba74b106SEric Auger /*
65*ba74b106SEric Auger  * init_cmd_queue - Allocate the command queue and initialize
66*ba74b106SEric Auger  * CBASER, CWRITER
67*ba74b106SEric Auger  */
68*ba74b106SEric Auger static void its_cmd_queue_init(void)
69*ba74b106SEric Auger {
70*ba74b106SEric Auger 	unsigned long order = get_order(SZ_64K >> PAGE_SHIFT);
71*ba74b106SEric Auger 	u64 cbaser;
72*ba74b106SEric Auger 
73*ba74b106SEric Auger 	its_data.cmd_base = alloc_pages(order);
74*ba74b106SEric Auger 
75*ba74b106SEric Auger 	cbaser = virt_to_phys(its_data.cmd_base) | (SZ_64K / SZ_4K - 1) | GITS_CBASER_VALID;
76*ba74b106SEric Auger 
77*ba74b106SEric Auger 	writeq(cbaser, its_data.base + GITS_CBASER);
78*ba74b106SEric Auger 
79*ba74b106SEric Auger 	its_data.cmd_write = its_data.cmd_base;
80*ba74b106SEric Auger 	writeq(0, its_data.base + GITS_CWRITER);
81*ba74b106SEric Auger }
82*ba74b106SEric Auger 
83*ba74b106SEric Auger void its_init(void)
84*ba74b106SEric Auger {
85*ba74b106SEric Auger 	if (!its_data.base)
86*ba74b106SEric Auger 		return;
87*ba74b106SEric Auger 
88*ba74b106SEric Auger 	its_parse_typer();
89*ba74b106SEric Auger 
90*ba74b106SEric Auger 	assert(!its_baser_lookup(GITS_BASER_TYPE_DEVICE, &its_data.device_baser));
91*ba74b106SEric Auger 	assert(!its_baser_lookup(GITS_BASER_TYPE_COLLECTION, &its_data.coll_baser));
92*ba74b106SEric Auger 
93*ba74b106SEric Auger 	its_baser_alloc_table(&its_data.device_baser, SZ_64K);
94*ba74b106SEric Auger 	its_baser_alloc_table(&its_data.coll_baser, SZ_64K);
95*ba74b106SEric Auger 
96*ba74b106SEric Auger 	its_cmd_queue_init();
97*ba74b106SEric Auger }
98*ba74b106SEric Auger 
99