xref: /kvm-unit-tests/lib/arm64/gic-v3-its.c (revision b4667f4ca26aea926a2ddecfcb5669e0e4e7cbf4)
1 /*
2  * Copyright (C) 2020, Red Hat Inc, Eric Auger <eric.auger@redhat.com>
3  *
4  * This work is licensed under the terms of the GNU LGPL, version 2.
5  */
6 #include <asm/gic.h>
7 #include <alloc_page.h>
8 
its_parse_typer(void)9 void its_parse_typer(void)
10 {
11 	u64 typer = readq(gicv3_its_base() + GITS_TYPER);
12 	struct its_typer *t = &its_data.typer;
13 
14 	t->ite_size = ((typer & GITS_TYPER_ITT_ENTRY_SIZE) >> GITS_TYPER_ITT_ENTRY_SIZE_SHIFT) + 1;
15 	t->pta = typer & GITS_TYPER_PTA;
16 	t->eventid_bits = ((typer & GITS_TYPER_IDBITS) >> GITS_TYPER_IDBITS_SHIFT) + 1;
17 	t->deviceid_bits = ((typer & GITS_TYPER_DEVBITS) >> GITS_TYPER_DEVBITS_SHIFT) + 1;
18 
19 	if (typer & GITS_TYPER_CIL)
20 		t->collid_bits = ((typer & GITS_TYPER_CIDBITS) >> GITS_TYPER_CIDBITS_SHIFT) + 1;
21 	else
22 		t->collid_bits = 16;
23 
24 	t->virt_lpi = typer & GITS_TYPER_VLPIS;
25 	t->phys_lpi = typer & GITS_TYPER_PLPIS;
26 }
27 
its_baser_lookup(int type,struct its_baser * baser)28 int its_baser_lookup(int type, struct its_baser *baser)
29 {
30 	int i;
31 
32 	for (i = 0; i < GITS_BASER_NR_REGS; i++) {
33 		void *reg_addr = gicv3_its_base() + GITS_BASER + i * 8;
34 		u64 val = readq(reg_addr);
35 
36 		if (GITS_BASER_TYPE(val) == type) {
37 			assert((val & GITS_BASER_PAGE_SIZE_MASK) == GITS_BASER_PAGE_SIZE_64K);
38 			baser->esz = GITS_BASER_ENTRY_SIZE(val);
39 			baser->indirect = val & GITS_BASER_INDIRECT;
40 			baser->index = i;
41 			return 0;
42 		}
43 	}
44 	return -1;
45 }
46 
47 /*
48  * Allocate the BASER table (a single page of size @baser->psz)
49  * and set the BASER valid
50  */
its_baser_alloc_table(struct its_baser * baser,size_t size)51 static void its_baser_alloc_table(struct its_baser *baser, size_t size)
52 {
53 	unsigned long order = get_order(size >> PAGE_SHIFT);
54 	void *reg_addr = gicv3_its_base() + GITS_BASER + baser->index * 8;
55 	u64 val = readq(reg_addr);
56 
57 	baser->table_addr = alloc_pages(order);
58 
59 	val |= virt_to_phys(baser->table_addr) | GITS_BASER_VALID;
60 
61 	writeq(val, reg_addr);
62 }
63 
64 /*
65  * init_cmd_queue - Allocate the command queue and initialize
66  * CBASER, CWRITER
67  */
its_cmd_queue_init(void)68 static void its_cmd_queue_init(void)
69 {
70 	unsigned long order = get_order(SZ_64K >> PAGE_SHIFT);
71 	u64 cbaser;
72 
73 	its_data.cmd_base = alloc_pages(order);
74 
75 	cbaser = virt_to_phys(its_data.cmd_base) | (SZ_64K / SZ_4K - 1) | GITS_CBASER_VALID;
76 
77 	writeq(cbaser, its_data.base + GITS_CBASER);
78 
79 	its_data.cmd_write = its_data.cmd_base;
80 	writeq(0, its_data.base + GITS_CWRITER);
81 }
82 
its_init(void)83 void its_init(void)
84 {
85 	if (!its_data.base)
86 		return;
87 
88 	its_parse_typer();
89 
90 	assert(!its_baser_lookup(GITS_BASER_TYPE_DEVICE, &its_data.device_baser));
91 	assert(!its_baser_lookup(GITS_BASER_TYPE_COLLECTION, &its_data.coll_baser));
92 
93 	its_baser_alloc_table(&its_data.device_baser, SZ_64K);
94 	its_baser_alloc_table(&its_data.coll_baser, SZ_64K);
95 
96 	its_cmd_queue_init();
97 }
98 
99 /* must be called after gicv3_enable_defaults */
its_enable_defaults(void)100 void its_enable_defaults(void)
101 {
102 	int cpu;
103 
104 	/* Allocate LPI config and pending tables */
105 	gicv3_lpi_alloc_tables();
106 
107 	for_each_online_cpu(cpu)
108 		gicv3_lpi_rdist_enable(cpu);
109 
110 	writel(GITS_CTLR_ENABLE, its_data.base + GITS_CTLR);
111 }
112 
its_create_device(u32 device_id,int nr_ites)113 struct its_device *its_create_device(u32 device_id, int nr_ites)
114 {
115 	struct its_device *new;
116 	unsigned long n;
117 
118 	assert(its_data.nr_devices < GITS_MAX_DEVICES);
119 
120 	new = &its_data.devices[its_data.nr_devices];
121 
122 	new->device_id = device_id;
123 	new->nr_ites = nr_ites;
124 
125 	n = (its_data.typer.ite_size * nr_ites) >> PAGE_SHIFT;
126 	new->itt = alloc_pages(get_order(n));
127 
128 	its_data.nr_devices++;
129 	return new;
130 }
131 
its_create_collection(u16 col_id,u32 pe)132 struct its_collection *its_create_collection(u16 col_id, u32 pe)
133 {
134 	struct its_collection *new;
135 
136 	assert(its_data.nr_collections < GITS_MAX_COLLECTIONS);
137 
138 	new = &its_data.collections[its_data.nr_collections];
139 
140 	new->col_id = col_id;
141 
142 	if (its_data.typer.pta)
143 		new->target_address = (u64)gicv3_data.redist_base[pe];
144 	else
145 		new->target_address = pe << 16;
146 
147 	its_data.nr_collections++;
148 	return new;
149 }
150 
its_get_device(u32 id)151 struct its_device *its_get_device(u32 id)
152 {
153 	int i;
154 
155 	for (i = 0; i < GITS_MAX_DEVICES; i++) {
156 		if (its_data.devices[i].device_id == id)
157 			return &its_data.devices[i];
158 	}
159 	assert(0);
160 }
161 
its_get_collection(u32 id)162 struct its_collection *its_get_collection(u32 id)
163 {
164 	int i;
165 
166 	for (i = 0; i < GITS_MAX_COLLECTIONS; i++) {
167 		if (its_data.collections[i].col_id == id)
168 			return &its_data.collections[i];
169 	}
170 	assert(0);
171 }
172