xref: /kvm-unit-tests/lib/x86/intel-iommu.c (revision 16c0b05f0586b9c66e0c6b2ce7657bf98486af27)
1*16c0b05fSPeter Xu /*
2*16c0b05fSPeter Xu  * Intel IOMMU APIs
3*16c0b05fSPeter Xu  *
4*16c0b05fSPeter Xu  * Copyright (C) 2016 Red Hat, Inc.
5*16c0b05fSPeter Xu  *
6*16c0b05fSPeter Xu  * Authors:
7*16c0b05fSPeter Xu  *   Peter Xu <peterx@redhat.com>,
8*16c0b05fSPeter Xu  *
9*16c0b05fSPeter Xu  * This work is licensed under the terms of the GNU LGPL, version 2 or
10*16c0b05fSPeter Xu  * later.
11*16c0b05fSPeter Xu  */
12*16c0b05fSPeter Xu 
13*16c0b05fSPeter Xu #include "intel-iommu.h"
14*16c0b05fSPeter Xu 
15*16c0b05fSPeter Xu #define VTD_RTA_MASK  (PAGE_MASK)
16*16c0b05fSPeter Xu #define VTD_IRTA_MASK (PAGE_MASK)
17*16c0b05fSPeter Xu 
18*16c0b05fSPeter Xu void *vtd_reg_base;
19*16c0b05fSPeter Xu 
20*16c0b05fSPeter Xu static uint64_t vtd_root_table(void)
21*16c0b05fSPeter Xu {
22*16c0b05fSPeter Xu 	/* No extend root table support yet */
23*16c0b05fSPeter Xu 	return vtd_readq(DMAR_RTADDR_REG) & VTD_RTA_MASK;
24*16c0b05fSPeter Xu }
25*16c0b05fSPeter Xu 
26*16c0b05fSPeter Xu static uint64_t vtd_ir_table(void)
27*16c0b05fSPeter Xu {
28*16c0b05fSPeter Xu 	return vtd_readq(DMAR_IRTA_REG) & VTD_IRTA_MASK;
29*16c0b05fSPeter Xu }
30*16c0b05fSPeter Xu 
31*16c0b05fSPeter Xu static void vtd_gcmd_or(uint32_t cmd)
32*16c0b05fSPeter Xu {
33*16c0b05fSPeter Xu 	uint32_t status;
34*16c0b05fSPeter Xu 
35*16c0b05fSPeter Xu 	/* We only allow set one bit for each time */
36*16c0b05fSPeter Xu 	assert(is_power_of_2(cmd));
37*16c0b05fSPeter Xu 
38*16c0b05fSPeter Xu 	status = vtd_readl(DMAR_GSTS_REG);
39*16c0b05fSPeter Xu 	vtd_writel(DMAR_GCMD_REG, status | cmd);
40*16c0b05fSPeter Xu 
41*16c0b05fSPeter Xu 	if (cmd & VTD_GCMD_ONE_SHOT_BITS) {
42*16c0b05fSPeter Xu 		/* One-shot bits are taking effect immediately */
43*16c0b05fSPeter Xu 		return;
44*16c0b05fSPeter Xu 	}
45*16c0b05fSPeter Xu 
46*16c0b05fSPeter Xu 	/* Make sure IOMMU handled our command request */
47*16c0b05fSPeter Xu 	while (!(vtd_readl(DMAR_GSTS_REG) & cmd))
48*16c0b05fSPeter Xu 		cpu_relax();
49*16c0b05fSPeter Xu }
50*16c0b05fSPeter Xu 
51*16c0b05fSPeter Xu static void vtd_dump_init_info(void)
52*16c0b05fSPeter Xu {
53*16c0b05fSPeter Xu 	uint32_t version;
54*16c0b05fSPeter Xu 
55*16c0b05fSPeter Xu 	version = vtd_readl(DMAR_VER_REG);
56*16c0b05fSPeter Xu 
57*16c0b05fSPeter Xu 	/* Major version >= 1 */
58*16c0b05fSPeter Xu 	assert(((version >> 3) & 0xf) >= 1);
59*16c0b05fSPeter Xu 
60*16c0b05fSPeter Xu 	printf("VT-d version:   0x%x\n", version);
61*16c0b05fSPeter Xu 	printf("     cap:       0x%016lx\n", vtd_readq(DMAR_CAP_REG));
62*16c0b05fSPeter Xu 	printf("     ecap:      0x%016lx\n", vtd_readq(DMAR_ECAP_REG));
63*16c0b05fSPeter Xu }
64*16c0b05fSPeter Xu 
65*16c0b05fSPeter Xu static void vtd_setup_root_table(void)
66*16c0b05fSPeter Xu {
67*16c0b05fSPeter Xu 	void *root = alloc_page();
68*16c0b05fSPeter Xu 
69*16c0b05fSPeter Xu 	memset(root, 0, PAGE_SIZE);
70*16c0b05fSPeter Xu 	vtd_writeq(DMAR_RTADDR_REG, virt_to_phys(root));
71*16c0b05fSPeter Xu 	vtd_gcmd_or(VTD_GCMD_ROOT);
72*16c0b05fSPeter Xu 	printf("DMAR table address: 0x%016lx\n", vtd_root_table());
73*16c0b05fSPeter Xu }
74*16c0b05fSPeter Xu 
75*16c0b05fSPeter Xu static void vtd_setup_ir_table(void)
76*16c0b05fSPeter Xu {
77*16c0b05fSPeter Xu 	void *root = alloc_page();
78*16c0b05fSPeter Xu 
79*16c0b05fSPeter Xu 	memset(root, 0, PAGE_SIZE);
80*16c0b05fSPeter Xu 	/* 0xf stands for table size (2^(0xf+1) == 65536) */
81*16c0b05fSPeter Xu 	vtd_writeq(DMAR_IRTA_REG, virt_to_phys(root) | 0xf);
82*16c0b05fSPeter Xu 	vtd_gcmd_or(VTD_GCMD_IR_TABLE);
83*16c0b05fSPeter Xu 	printf("IR table address: 0x%016lx\n", vtd_ir_table());
84*16c0b05fSPeter Xu }
85*16c0b05fSPeter Xu 
86*16c0b05fSPeter Xu void vtd_init(void)
87*16c0b05fSPeter Xu {
88*16c0b05fSPeter Xu 	setup_vm();
89*16c0b05fSPeter Xu 	smp_init();
90*16c0b05fSPeter Xu 
91*16c0b05fSPeter Xu 	vtd_reg_base = ioremap(Q35_HOST_BRIDGE_IOMMU_ADDR, PAGE_SIZE);
92*16c0b05fSPeter Xu 
93*16c0b05fSPeter Xu 	vtd_dump_init_info();
94*16c0b05fSPeter Xu 	vtd_gcmd_or(VTD_GCMD_QI); /* Enable QI */
95*16c0b05fSPeter Xu 	vtd_setup_root_table();
96*16c0b05fSPeter Xu 	vtd_setup_ir_table();
97*16c0b05fSPeter Xu 	vtd_gcmd_or(VTD_GCMD_DMAR); /* Enable DMAR */
98*16c0b05fSPeter Xu 	vtd_gcmd_or(VTD_GCMD_IR);   /* Enable IR */
99*16c0b05fSPeter Xu }
100