xref: /linux/tools/testing/selftests/kvm/lib/arm64/gic_v3_its.c (revision 1260ed77798502de9c98020040d2995008de10cc)
1*67730e6cSSean Christopherson // SPDX-License-Identifier: GPL-2.0
2*67730e6cSSean Christopherson /*
3*67730e6cSSean Christopherson  * Guest ITS library, generously donated by drivers/irqchip/irq-gic-v3-its.c
4*67730e6cSSean Christopherson  * over in the kernel tree.
5*67730e6cSSean Christopherson  */
6*67730e6cSSean Christopherson 
7*67730e6cSSean Christopherson #include <linux/kvm.h>
8*67730e6cSSean Christopherson #include <linux/sizes.h>
9*67730e6cSSean Christopherson #include <asm/kvm_para.h>
10*67730e6cSSean Christopherson #include <asm/kvm.h>
11*67730e6cSSean Christopherson 
12*67730e6cSSean Christopherson #include "kvm_util.h"
13*67730e6cSSean Christopherson #include "vgic.h"
14*67730e6cSSean Christopherson #include "gic.h"
15*67730e6cSSean Christopherson #include "gic_v3.h"
16*67730e6cSSean Christopherson #include "processor.h"
17*67730e6cSSean Christopherson 
18*67730e6cSSean Christopherson static u64 its_read_u64(unsigned long offset)
19*67730e6cSSean Christopherson {
20*67730e6cSSean Christopherson 	return readq_relaxed(GITS_BASE_GVA + offset);
21*67730e6cSSean Christopherson }
22*67730e6cSSean Christopherson 
23*67730e6cSSean Christopherson static void its_write_u64(unsigned long offset, u64 val)
24*67730e6cSSean Christopherson {
25*67730e6cSSean Christopherson 	writeq_relaxed(val, GITS_BASE_GVA + offset);
26*67730e6cSSean Christopherson }
27*67730e6cSSean Christopherson 
28*67730e6cSSean Christopherson static u32 its_read_u32(unsigned long offset)
29*67730e6cSSean Christopherson {
30*67730e6cSSean Christopherson 	return readl_relaxed(GITS_BASE_GVA + offset);
31*67730e6cSSean Christopherson }
32*67730e6cSSean Christopherson 
33*67730e6cSSean Christopherson static void its_write_u32(unsigned long offset, u32 val)
34*67730e6cSSean Christopherson {
35*67730e6cSSean Christopherson 	writel_relaxed(val, GITS_BASE_GVA + offset);
36*67730e6cSSean Christopherson }
37*67730e6cSSean Christopherson 
38*67730e6cSSean Christopherson static unsigned long its_find_baser(unsigned int type)
39*67730e6cSSean Christopherson {
40*67730e6cSSean Christopherson 	int i;
41*67730e6cSSean Christopherson 
42*67730e6cSSean Christopherson 	for (i = 0; i < GITS_BASER_NR_REGS; i++) {
43*67730e6cSSean Christopherson 		u64 baser;
44*67730e6cSSean Christopherson 		unsigned long offset = GITS_BASER + (i * sizeof(baser));
45*67730e6cSSean Christopherson 
46*67730e6cSSean Christopherson 		baser = its_read_u64(offset);
47*67730e6cSSean Christopherson 		if (GITS_BASER_TYPE(baser) == type)
48*67730e6cSSean Christopherson 			return offset;
49*67730e6cSSean Christopherson 	}
50*67730e6cSSean Christopherson 
51*67730e6cSSean Christopherson 	GUEST_FAIL("Couldn't find an ITS BASER of type %u", type);
52*67730e6cSSean Christopherson 	return -1;
53*67730e6cSSean Christopherson }
54*67730e6cSSean Christopherson 
55*67730e6cSSean Christopherson static void its_install_table(unsigned int type, vm_paddr_t base, size_t size)
56*67730e6cSSean Christopherson {
57*67730e6cSSean Christopherson 	unsigned long offset = its_find_baser(type);
58*67730e6cSSean Christopherson 	u64 baser;
59*67730e6cSSean Christopherson 
60*67730e6cSSean Christopherson 	baser = ((size / SZ_64K) - 1) |
61*67730e6cSSean Christopherson 		GITS_BASER_PAGE_SIZE_64K |
62*67730e6cSSean Christopherson 		GITS_BASER_InnerShareable |
63*67730e6cSSean Christopherson 		base |
64*67730e6cSSean Christopherson 		GITS_BASER_RaWaWb |
65*67730e6cSSean Christopherson 		GITS_BASER_VALID;
66*67730e6cSSean Christopherson 
67*67730e6cSSean Christopherson 	its_write_u64(offset, baser);
68*67730e6cSSean Christopherson }
69*67730e6cSSean Christopherson 
70*67730e6cSSean Christopherson static void its_install_cmdq(vm_paddr_t base, size_t size)
71*67730e6cSSean Christopherson {
72*67730e6cSSean Christopherson 	u64 cbaser;
73*67730e6cSSean Christopherson 
74*67730e6cSSean Christopherson 	cbaser = ((size / SZ_4K) - 1) |
75*67730e6cSSean Christopherson 		 GITS_CBASER_InnerShareable |
76*67730e6cSSean Christopherson 		 base |
77*67730e6cSSean Christopherson 		 GITS_CBASER_RaWaWb |
78*67730e6cSSean Christopherson 		 GITS_CBASER_VALID;
79*67730e6cSSean Christopherson 
80*67730e6cSSean Christopherson 	its_write_u64(GITS_CBASER, cbaser);
81*67730e6cSSean Christopherson }
82*67730e6cSSean Christopherson 
83*67730e6cSSean Christopherson void its_init(vm_paddr_t coll_tbl, size_t coll_tbl_sz,
84*67730e6cSSean Christopherson 	      vm_paddr_t device_tbl, size_t device_tbl_sz,
85*67730e6cSSean Christopherson 	      vm_paddr_t cmdq, size_t cmdq_size)
86*67730e6cSSean Christopherson {
87*67730e6cSSean Christopherson 	u32 ctlr;
88*67730e6cSSean Christopherson 
89*67730e6cSSean Christopherson 	its_install_table(GITS_BASER_TYPE_COLLECTION, coll_tbl, coll_tbl_sz);
90*67730e6cSSean Christopherson 	its_install_table(GITS_BASER_TYPE_DEVICE, device_tbl, device_tbl_sz);
91*67730e6cSSean Christopherson 	its_install_cmdq(cmdq, cmdq_size);
92*67730e6cSSean Christopherson 
93*67730e6cSSean Christopherson 	ctlr = its_read_u32(GITS_CTLR);
94*67730e6cSSean Christopherson 	ctlr |= GITS_CTLR_ENABLE;
95*67730e6cSSean Christopherson 	its_write_u32(GITS_CTLR, ctlr);
96*67730e6cSSean Christopherson }
97*67730e6cSSean Christopherson 
98*67730e6cSSean Christopherson struct its_cmd_block {
99*67730e6cSSean Christopherson 	union {
100*67730e6cSSean Christopherson 		u64	raw_cmd[4];
101*67730e6cSSean Christopherson 		__le64	raw_cmd_le[4];
102*67730e6cSSean Christopherson 	};
103*67730e6cSSean Christopherson };
104*67730e6cSSean Christopherson 
105*67730e6cSSean Christopherson static inline void its_fixup_cmd(struct its_cmd_block *cmd)
106*67730e6cSSean Christopherson {
107*67730e6cSSean Christopherson 	/* Let's fixup BE commands */
108*67730e6cSSean Christopherson 	cmd->raw_cmd_le[0] = cpu_to_le64(cmd->raw_cmd[0]);
109*67730e6cSSean Christopherson 	cmd->raw_cmd_le[1] = cpu_to_le64(cmd->raw_cmd[1]);
110*67730e6cSSean Christopherson 	cmd->raw_cmd_le[2] = cpu_to_le64(cmd->raw_cmd[2]);
111*67730e6cSSean Christopherson 	cmd->raw_cmd_le[3] = cpu_to_le64(cmd->raw_cmd[3]);
112*67730e6cSSean Christopherson }
113*67730e6cSSean Christopherson 
114*67730e6cSSean Christopherson static void its_mask_encode(u64 *raw_cmd, u64 val, int h, int l)
115*67730e6cSSean Christopherson {
116*67730e6cSSean Christopherson 	u64 mask = GENMASK_ULL(h, l);
117*67730e6cSSean Christopherson 	*raw_cmd &= ~mask;
118*67730e6cSSean Christopherson 	*raw_cmd |= (val << l) & mask;
119*67730e6cSSean Christopherson }
120*67730e6cSSean Christopherson 
121*67730e6cSSean Christopherson static void its_encode_cmd(struct its_cmd_block *cmd, u8 cmd_nr)
122*67730e6cSSean Christopherson {
123*67730e6cSSean Christopherson 	its_mask_encode(&cmd->raw_cmd[0], cmd_nr, 7, 0);
124*67730e6cSSean Christopherson }
125*67730e6cSSean Christopherson 
126*67730e6cSSean Christopherson static void its_encode_devid(struct its_cmd_block *cmd, u32 devid)
127*67730e6cSSean Christopherson {
128*67730e6cSSean Christopherson 	its_mask_encode(&cmd->raw_cmd[0], devid, 63, 32);
129*67730e6cSSean Christopherson }
130*67730e6cSSean Christopherson 
131*67730e6cSSean Christopherson static void its_encode_event_id(struct its_cmd_block *cmd, u32 id)
132*67730e6cSSean Christopherson {
133*67730e6cSSean Christopherson 	its_mask_encode(&cmd->raw_cmd[1], id, 31, 0);
134*67730e6cSSean Christopherson }
135*67730e6cSSean Christopherson 
136*67730e6cSSean Christopherson static void its_encode_phys_id(struct its_cmd_block *cmd, u32 phys_id)
137*67730e6cSSean Christopherson {
138*67730e6cSSean Christopherson 	its_mask_encode(&cmd->raw_cmd[1], phys_id, 63, 32);
139*67730e6cSSean Christopherson }
140*67730e6cSSean Christopherson 
141*67730e6cSSean Christopherson static void its_encode_size(struct its_cmd_block *cmd, u8 size)
142*67730e6cSSean Christopherson {
143*67730e6cSSean Christopherson 	its_mask_encode(&cmd->raw_cmd[1], size, 4, 0);
144*67730e6cSSean Christopherson }
145*67730e6cSSean Christopherson 
146*67730e6cSSean Christopherson static void its_encode_itt(struct its_cmd_block *cmd, u64 itt_addr)
147*67730e6cSSean Christopherson {
148*67730e6cSSean Christopherson 	its_mask_encode(&cmd->raw_cmd[2], itt_addr >> 8, 51, 8);
149*67730e6cSSean Christopherson }
150*67730e6cSSean Christopherson 
151*67730e6cSSean Christopherson static void its_encode_valid(struct its_cmd_block *cmd, int valid)
152*67730e6cSSean Christopherson {
153*67730e6cSSean Christopherson 	its_mask_encode(&cmd->raw_cmd[2], !!valid, 63, 63);
154*67730e6cSSean Christopherson }
155*67730e6cSSean Christopherson 
156*67730e6cSSean Christopherson static void its_encode_target(struct its_cmd_block *cmd, u64 target_addr)
157*67730e6cSSean Christopherson {
158*67730e6cSSean Christopherson 	its_mask_encode(&cmd->raw_cmd[2], target_addr >> 16, 51, 16);
159*67730e6cSSean Christopherson }
160*67730e6cSSean Christopherson 
161*67730e6cSSean Christopherson static void its_encode_collection(struct its_cmd_block *cmd, u16 col)
162*67730e6cSSean Christopherson {
163*67730e6cSSean Christopherson 	its_mask_encode(&cmd->raw_cmd[2], col, 15, 0);
164*67730e6cSSean Christopherson }
165*67730e6cSSean Christopherson 
166*67730e6cSSean Christopherson #define GITS_CMDQ_POLL_ITERATIONS	0
167*67730e6cSSean Christopherson 
168*67730e6cSSean Christopherson static void its_send_cmd(void *cmdq_base, struct its_cmd_block *cmd)
169*67730e6cSSean Christopherson {
170*67730e6cSSean Christopherson 	u64 cwriter = its_read_u64(GITS_CWRITER);
171*67730e6cSSean Christopherson 	struct its_cmd_block *dst = cmdq_base + cwriter;
172*67730e6cSSean Christopherson 	u64 cbaser = its_read_u64(GITS_CBASER);
173*67730e6cSSean Christopherson 	size_t cmdq_size;
174*67730e6cSSean Christopherson 	u64 next;
175*67730e6cSSean Christopherson 	int i;
176*67730e6cSSean Christopherson 
177*67730e6cSSean Christopherson 	cmdq_size = ((cbaser & 0xFF) + 1) * SZ_4K;
178*67730e6cSSean Christopherson 
179*67730e6cSSean Christopherson 	its_fixup_cmd(cmd);
180*67730e6cSSean Christopherson 
181*67730e6cSSean Christopherson 	WRITE_ONCE(*dst, *cmd);
182*67730e6cSSean Christopherson 	dsb(ishst);
183*67730e6cSSean Christopherson 	next = (cwriter + sizeof(*cmd)) % cmdq_size;
184*67730e6cSSean Christopherson 	its_write_u64(GITS_CWRITER, next);
185*67730e6cSSean Christopherson 
186*67730e6cSSean Christopherson 	/*
187*67730e6cSSean Christopherson 	 * Polling isn't necessary considering KVM's ITS emulation at the time
188*67730e6cSSean Christopherson 	 * of writing this, as the CMDQ is processed synchronously after a write
189*67730e6cSSean Christopherson 	 * to CWRITER.
190*67730e6cSSean Christopherson 	 */
191*67730e6cSSean Christopherson 	for (i = 0; its_read_u64(GITS_CREADR) != next; i++) {
192*67730e6cSSean Christopherson 		__GUEST_ASSERT(i < GITS_CMDQ_POLL_ITERATIONS,
193*67730e6cSSean Christopherson 			       "ITS didn't process command at offset %lu after %d iterations\n",
194*67730e6cSSean Christopherson 			       cwriter, i);
195*67730e6cSSean Christopherson 
196*67730e6cSSean Christopherson 		cpu_relax();
197*67730e6cSSean Christopherson 	}
198*67730e6cSSean Christopherson }
199*67730e6cSSean Christopherson 
200*67730e6cSSean Christopherson void its_send_mapd_cmd(void *cmdq_base, u32 device_id, vm_paddr_t itt_base,
201*67730e6cSSean Christopherson 		       size_t itt_size, bool valid)
202*67730e6cSSean Christopherson {
203*67730e6cSSean Christopherson 	struct its_cmd_block cmd = {};
204*67730e6cSSean Christopherson 
205*67730e6cSSean Christopherson 	its_encode_cmd(&cmd, GITS_CMD_MAPD);
206*67730e6cSSean Christopherson 	its_encode_devid(&cmd, device_id);
207*67730e6cSSean Christopherson 	its_encode_size(&cmd, ilog2(itt_size) - 1);
208*67730e6cSSean Christopherson 	its_encode_itt(&cmd, itt_base);
209*67730e6cSSean Christopherson 	its_encode_valid(&cmd, valid);
210*67730e6cSSean Christopherson 
211*67730e6cSSean Christopherson 	its_send_cmd(cmdq_base, &cmd);
212*67730e6cSSean Christopherson }
213*67730e6cSSean Christopherson 
214*67730e6cSSean Christopherson void its_send_mapc_cmd(void *cmdq_base, u32 vcpu_id, u32 collection_id, bool valid)
215*67730e6cSSean Christopherson {
216*67730e6cSSean Christopherson 	struct its_cmd_block cmd = {};
217*67730e6cSSean Christopherson 
218*67730e6cSSean Christopherson 	its_encode_cmd(&cmd, GITS_CMD_MAPC);
219*67730e6cSSean Christopherson 	its_encode_collection(&cmd, collection_id);
220*67730e6cSSean Christopherson 	its_encode_target(&cmd, vcpu_id);
221*67730e6cSSean Christopherson 	its_encode_valid(&cmd, valid);
222*67730e6cSSean Christopherson 
223*67730e6cSSean Christopherson 	its_send_cmd(cmdq_base, &cmd);
224*67730e6cSSean Christopherson }
225*67730e6cSSean Christopherson 
226*67730e6cSSean Christopherson void its_send_mapti_cmd(void *cmdq_base, u32 device_id, u32 event_id,
227*67730e6cSSean Christopherson 			u32 collection_id, u32 intid)
228*67730e6cSSean Christopherson {
229*67730e6cSSean Christopherson 	struct its_cmd_block cmd = {};
230*67730e6cSSean Christopherson 
231*67730e6cSSean Christopherson 	its_encode_cmd(&cmd, GITS_CMD_MAPTI);
232*67730e6cSSean Christopherson 	its_encode_devid(&cmd, device_id);
233*67730e6cSSean Christopherson 	its_encode_event_id(&cmd, event_id);
234*67730e6cSSean Christopherson 	its_encode_phys_id(&cmd, intid);
235*67730e6cSSean Christopherson 	its_encode_collection(&cmd, collection_id);
236*67730e6cSSean Christopherson 
237*67730e6cSSean Christopherson 	its_send_cmd(cmdq_base, &cmd);
238*67730e6cSSean Christopherson }
239*67730e6cSSean Christopherson 
240*67730e6cSSean Christopherson void its_send_invall_cmd(void *cmdq_base, u32 collection_id)
241*67730e6cSSean Christopherson {
242*67730e6cSSean Christopherson 	struct its_cmd_block cmd = {};
243*67730e6cSSean Christopherson 
244*67730e6cSSean Christopherson 	its_encode_cmd(&cmd, GITS_CMD_INVALL);
245*67730e6cSSean Christopherson 	its_encode_collection(&cmd, collection_id);
246*67730e6cSSean Christopherson 
247*67730e6cSSean Christopherson 	its_send_cmd(cmdq_base, &cmd);
248*67730e6cSSean Christopherson }
249