xref: /kvm-unit-tests/lib/x86/intel-iommu.c (revision 3223ade219a6e1b927307022f4800832f24f5c86)
116c0b05fSPeter Xu /*
216c0b05fSPeter Xu  * Intel IOMMU APIs
316c0b05fSPeter Xu  *
416c0b05fSPeter Xu  * Copyright (C) 2016 Red Hat, Inc.
516c0b05fSPeter Xu  *
616c0b05fSPeter Xu  * Authors:
716c0b05fSPeter Xu  *   Peter Xu <peterx@redhat.com>,
816c0b05fSPeter Xu  *
916c0b05fSPeter Xu  * This work is licensed under the terms of the GNU LGPL, version 2 or
1016c0b05fSPeter Xu  * later.
1116c0b05fSPeter Xu  */
1216c0b05fSPeter Xu 
1316c0b05fSPeter Xu #include "intel-iommu.h"
1492d2c192SPeter Xu #include "libcflat.h"
157f2477c2SPeter Xu #include "pci.h"
16b4377753SPeter Xu #include "atomic.h"
1792d2c192SPeter Xu 
1892d2c192SPeter Xu /*
1992d2c192SPeter Xu  * VT-d in QEMU currently only support 39 bits address width, which is
2092d2c192SPeter Xu  * 3-level translation.
2192d2c192SPeter Xu  */
2292d2c192SPeter Xu #define VTD_PAGE_LEVEL      3
2392d2c192SPeter Xu #define VTD_CE_AW_39BIT     0x1
2492d2c192SPeter Xu 
2592d2c192SPeter Xu typedef uint64_t vtd_pte_t;
2692d2c192SPeter Xu 
2792d2c192SPeter Xu struct vtd_root_entry {
2892d2c192SPeter Xu 	/* Quad 1 */
2992d2c192SPeter Xu 	uint64_t present:1;
3092d2c192SPeter Xu 	uint64_t __reserved:11;
3192d2c192SPeter Xu 	uint64_t context_table_p:52;
3292d2c192SPeter Xu 	/* Quad 2 */
3392d2c192SPeter Xu 	uint64_t __reserved_2;
3492d2c192SPeter Xu } __attribute__ ((packed));
3592d2c192SPeter Xu typedef struct vtd_root_entry vtd_re_t;
3692d2c192SPeter Xu 
3792d2c192SPeter Xu struct vtd_context_entry {
3892d2c192SPeter Xu 	/* Quad 1 */
3992d2c192SPeter Xu 	uint64_t present:1;
4092d2c192SPeter Xu 	uint64_t disable_fault_report:1;
4192d2c192SPeter Xu 	uint64_t trans_type:2;
4292d2c192SPeter Xu 	uint64_t __reserved:8;
4392d2c192SPeter Xu 	uint64_t slptptr:52;
4492d2c192SPeter Xu 	/* Quad 2 */
4592d2c192SPeter Xu 	uint64_t addr_width:3;
4692d2c192SPeter Xu 	uint64_t __ignore:4;
4792d2c192SPeter Xu 	uint64_t __reserved_2:1;
4892d2c192SPeter Xu 	uint64_t domain_id:16;
4992d2c192SPeter Xu 	uint64_t __reserved_3:40;
5092d2c192SPeter Xu } __attribute__ ((packed));
5192d2c192SPeter Xu typedef struct vtd_context_entry vtd_ce_t;
5216c0b05fSPeter Xu 
537f2477c2SPeter Xu struct vtd_irte {
547f2477c2SPeter Xu 	uint32_t present:1;
557f2477c2SPeter Xu 	uint32_t fault_disable:1;    /* Fault Processing Disable */
567f2477c2SPeter Xu 	uint32_t dest_mode:1;        /* Destination Mode */
577f2477c2SPeter Xu 	uint32_t redir_hint:1;       /* Redirection Hint */
587f2477c2SPeter Xu 	uint32_t trigger_mode:1;     /* Trigger Mode */
597f2477c2SPeter Xu 	uint32_t delivery_mode:3;    /* Delivery Mode */
607f2477c2SPeter Xu 	uint32_t __avail:4;          /* Available spaces for software */
617f2477c2SPeter Xu 	uint32_t __reserved_0:3;     /* Reserved 0 */
627f2477c2SPeter Xu 	uint32_t irte_mode:1;        /* IRTE Mode */
637f2477c2SPeter Xu 	uint32_t vector:8;           /* Interrupt Vector */
647f2477c2SPeter Xu 	uint32_t __reserved_1:8;     /* Reserved 1 */
657f2477c2SPeter Xu 	uint32_t dest_id;            /* Destination ID */
667f2477c2SPeter Xu 	uint16_t source_id:16;       /* Source-ID */
677f2477c2SPeter Xu 	uint64_t sid_q:2;            /* Source-ID Qualifier */
687f2477c2SPeter Xu 	uint64_t sid_vtype:2;        /* Source-ID Validation Type */
697f2477c2SPeter Xu 	uint64_t __reserved_2:44;    /* Reserved 2 */
707f2477c2SPeter Xu } __attribute__ ((packed));
717f2477c2SPeter Xu typedef struct vtd_irte vtd_irte_t;
727f2477c2SPeter Xu 
7316c0b05fSPeter Xu #define VTD_RTA_MASK  (PAGE_MASK)
7416c0b05fSPeter Xu #define VTD_IRTA_MASK (PAGE_MASK)
7516c0b05fSPeter Xu 
7616c0b05fSPeter Xu void *vtd_reg_base;
7716c0b05fSPeter Xu 
7816c0b05fSPeter Xu static uint64_t vtd_root_table(void)
7916c0b05fSPeter Xu {
8016c0b05fSPeter Xu 	/* No extend root table support yet */
8116c0b05fSPeter Xu 	return vtd_readq(DMAR_RTADDR_REG) & VTD_RTA_MASK;
8216c0b05fSPeter Xu }
8316c0b05fSPeter Xu 
8416c0b05fSPeter Xu static uint64_t vtd_ir_table(void)
8516c0b05fSPeter Xu {
8616c0b05fSPeter Xu 	return vtd_readq(DMAR_IRTA_REG) & VTD_IRTA_MASK;
8716c0b05fSPeter Xu }
8816c0b05fSPeter Xu 
8916c0b05fSPeter Xu static void vtd_gcmd_or(uint32_t cmd)
9016c0b05fSPeter Xu {
9116c0b05fSPeter Xu 	uint32_t status;
9216c0b05fSPeter Xu 
9316c0b05fSPeter Xu 	/* We only allow set one bit for each time */
9416c0b05fSPeter Xu 	assert(is_power_of_2(cmd));
9516c0b05fSPeter Xu 
9616c0b05fSPeter Xu 	status = vtd_readl(DMAR_GSTS_REG);
9716c0b05fSPeter Xu 	vtd_writel(DMAR_GCMD_REG, status | cmd);
9816c0b05fSPeter Xu 
9916c0b05fSPeter Xu 	if (cmd & VTD_GCMD_ONE_SHOT_BITS) {
10016c0b05fSPeter Xu 		/* One-shot bits are taking effect immediately */
10116c0b05fSPeter Xu 		return;
10216c0b05fSPeter Xu 	}
10316c0b05fSPeter Xu 
10416c0b05fSPeter Xu 	/* Make sure IOMMU handled our command request */
10516c0b05fSPeter Xu 	while (!(vtd_readl(DMAR_GSTS_REG) & cmd))
10616c0b05fSPeter Xu 		cpu_relax();
10716c0b05fSPeter Xu }
10816c0b05fSPeter Xu 
10916c0b05fSPeter Xu static void vtd_dump_init_info(void)
11016c0b05fSPeter Xu {
11116c0b05fSPeter Xu 	uint32_t version;
11216c0b05fSPeter Xu 
11316c0b05fSPeter Xu 	version = vtd_readl(DMAR_VER_REG);
11416c0b05fSPeter Xu 
11516c0b05fSPeter Xu 	/* Major version >= 1 */
11616c0b05fSPeter Xu 	assert(((version >> 3) & 0xf) >= 1);
11716c0b05fSPeter Xu 
11816c0b05fSPeter Xu 	printf("VT-d version:   0x%x\n", version);
11916c0b05fSPeter Xu 	printf("     cap:       0x%016lx\n", vtd_readq(DMAR_CAP_REG));
12016c0b05fSPeter Xu 	printf("     ecap:      0x%016lx\n", vtd_readq(DMAR_ECAP_REG));
12116c0b05fSPeter Xu }
12216c0b05fSPeter Xu 
12316c0b05fSPeter Xu static void vtd_setup_root_table(void)
12416c0b05fSPeter Xu {
12516c0b05fSPeter Xu 	void *root = alloc_page();
12616c0b05fSPeter Xu 
12716c0b05fSPeter Xu 	memset(root, 0, PAGE_SIZE);
12816c0b05fSPeter Xu 	vtd_writeq(DMAR_RTADDR_REG, virt_to_phys(root));
12916c0b05fSPeter Xu 	vtd_gcmd_or(VTD_GCMD_ROOT);
13016c0b05fSPeter Xu 	printf("DMAR table address: 0x%016lx\n", vtd_root_table());
13116c0b05fSPeter Xu }
13216c0b05fSPeter Xu 
13316c0b05fSPeter Xu static void vtd_setup_ir_table(void)
13416c0b05fSPeter Xu {
13516c0b05fSPeter Xu 	void *root = alloc_page();
13616c0b05fSPeter Xu 
13716c0b05fSPeter Xu 	memset(root, 0, PAGE_SIZE);
13816c0b05fSPeter Xu 	/* 0xf stands for table size (2^(0xf+1) == 65536) */
13916c0b05fSPeter Xu 	vtd_writeq(DMAR_IRTA_REG, virt_to_phys(root) | 0xf);
14016c0b05fSPeter Xu 	vtd_gcmd_or(VTD_GCMD_IR_TABLE);
14116c0b05fSPeter Xu 	printf("IR table address: 0x%016lx\n", vtd_ir_table());
14216c0b05fSPeter Xu }
14316c0b05fSPeter Xu 
14492d2c192SPeter Xu static void vtd_install_pte(vtd_pte_t *root, iova_t iova,
14592d2c192SPeter Xu 			    phys_addr_t pa, int level_target)
14692d2c192SPeter Xu {
14792d2c192SPeter Xu 	int level;
14892d2c192SPeter Xu 	unsigned int offset;
14992d2c192SPeter Xu 	void *page;
15092d2c192SPeter Xu 
15192d2c192SPeter Xu 	for (level = VTD_PAGE_LEVEL; level > level_target; level--) {
15292d2c192SPeter Xu 		offset = PGDIR_OFFSET(iova, level);
15392d2c192SPeter Xu 		if (!(root[offset] & VTD_PTE_RW)) {
15492d2c192SPeter Xu 			page = alloc_page();
15592d2c192SPeter Xu 			memset(page, 0, PAGE_SIZE);
15692d2c192SPeter Xu 			root[offset] = virt_to_phys(page) | VTD_PTE_RW;
15792d2c192SPeter Xu 		}
15892d2c192SPeter Xu 		root = (uint64_t *)(phys_to_virt(root[offset] &
15992d2c192SPeter Xu 						 VTD_PTE_ADDR));
16092d2c192SPeter Xu 	}
16192d2c192SPeter Xu 
16292d2c192SPeter Xu 	offset = PGDIR_OFFSET(iova, level);
16392d2c192SPeter Xu 	root[offset] = pa | VTD_PTE_RW;
16492d2c192SPeter Xu 	if (level != 1) {
16592d2c192SPeter Xu 		/* This is huge page */
16692d2c192SPeter Xu 		root[offset] |= VTD_PTE_HUGE;
16792d2c192SPeter Xu 	}
16892d2c192SPeter Xu }
16992d2c192SPeter Xu 
17092d2c192SPeter Xu #define  VTD_PHYS_TO_VIRT(x) \
17192d2c192SPeter Xu 	((void *)(((uint64_t)phys_to_virt(x)) >> VTD_PAGE_SHIFT))
17292d2c192SPeter Xu 
17392d2c192SPeter Xu /**
17492d2c192SPeter Xu  * vtd_map_range: setup IO address mapping for specific memory range
17592d2c192SPeter Xu  *
17692d2c192SPeter Xu  * @sid: source ID of the device to setup
17792d2c192SPeter Xu  * @iova: start IO virtual address
17892d2c192SPeter Xu  * @pa: start physical address
17992d2c192SPeter Xu  * @size: size of the mapping area
18092d2c192SPeter Xu  */
18192d2c192SPeter Xu void vtd_map_range(uint16_t sid, iova_t iova, phys_addr_t pa, size_t size)
18292d2c192SPeter Xu {
18392d2c192SPeter Xu 	uint8_t bus_n, devfn;
18492d2c192SPeter Xu 	void *slptptr;
18592d2c192SPeter Xu 	vtd_ce_t *ce;
18692d2c192SPeter Xu 	vtd_re_t *re = phys_to_virt(vtd_root_table());
18792d2c192SPeter Xu 
18892d2c192SPeter Xu 	assert(IS_ALIGNED(iova, SZ_4K));
18992d2c192SPeter Xu 	assert(IS_ALIGNED(pa, SZ_4K));
19092d2c192SPeter Xu 	assert(IS_ALIGNED(size, SZ_4K));
19192d2c192SPeter Xu 
19292d2c192SPeter Xu 	bus_n = PCI_BDF_GET_BUS(sid);
19392d2c192SPeter Xu 	devfn = PCI_BDF_GET_DEVFN(sid);
19492d2c192SPeter Xu 
19592d2c192SPeter Xu 	/* Point to the correct root entry */
19692d2c192SPeter Xu 	re += bus_n;
19792d2c192SPeter Xu 
19892d2c192SPeter Xu 	if (!re->present) {
19992d2c192SPeter Xu 		ce = alloc_page();
20092d2c192SPeter Xu 		memset(ce, 0, PAGE_SIZE);
20192d2c192SPeter Xu 		memset(re, 0, sizeof(*re));
20292d2c192SPeter Xu 		re->context_table_p = virt_to_phys(ce) >> VTD_PAGE_SHIFT;
20392d2c192SPeter Xu 		re->present = 1;
20492d2c192SPeter Xu 		printf("allocated vt-d root entry for PCI bus %d\n",
20592d2c192SPeter Xu 		       bus_n);
20692d2c192SPeter Xu 	} else
20792d2c192SPeter Xu 		ce = VTD_PHYS_TO_VIRT(re->context_table_p);
20892d2c192SPeter Xu 
20992d2c192SPeter Xu 	/* Point to the correct context entry */
21092d2c192SPeter Xu 	ce += devfn;
21192d2c192SPeter Xu 
21292d2c192SPeter Xu 	if (!ce->present) {
21392d2c192SPeter Xu 		slptptr = alloc_page();
21492d2c192SPeter Xu 		memset(slptptr, 0, PAGE_SIZE);
21592d2c192SPeter Xu 		memset(ce, 0, sizeof(*ce));
21692d2c192SPeter Xu 		/* To make it simple, domain ID is the same as SID */
21792d2c192SPeter Xu 		ce->domain_id = sid;
21892d2c192SPeter Xu 		/* We only test 39 bits width case (3-level paging) */
21992d2c192SPeter Xu 		ce->addr_width = VTD_CE_AW_39BIT;
22092d2c192SPeter Xu 		ce->slptptr = virt_to_phys(slptptr) >> VTD_PAGE_SHIFT;
22192d2c192SPeter Xu 		ce->trans_type = VTD_CONTEXT_TT_MULTI_LEVEL;
22292d2c192SPeter Xu 		ce->present = 1;
22392d2c192SPeter Xu 		/* No error reporting yet */
22492d2c192SPeter Xu 		ce->disable_fault_report = 1;
22592d2c192SPeter Xu 		printf("allocated vt-d context entry for devfn 0x%x\n",
22692d2c192SPeter Xu 		       devfn);
22792d2c192SPeter Xu 	} else
22892d2c192SPeter Xu 		slptptr = VTD_PHYS_TO_VIRT(ce->slptptr);
22992d2c192SPeter Xu 
23092d2c192SPeter Xu 	while (size) {
23192d2c192SPeter Xu 		/* TODO: currently we only map 4K pages (level = 1) */
23292d2c192SPeter Xu 		printf("map 4K page IOVA 0x%lx to 0x%lx (sid=0x%04x)\n",
23392d2c192SPeter Xu 		       iova, pa, sid);
23492d2c192SPeter Xu 		vtd_install_pte(slptptr, iova, pa, 1);
23592d2c192SPeter Xu 		size -= VTD_PAGE_SIZE;
23692d2c192SPeter Xu 		iova += VTD_PAGE_SIZE;
23792d2c192SPeter Xu 		pa += VTD_PAGE_SIZE;
23892d2c192SPeter Xu 	}
23992d2c192SPeter Xu }
24092d2c192SPeter Xu 
2417f2477c2SPeter Xu static uint16_t vtd_intr_index_alloc(void)
2427f2477c2SPeter Xu {
243b4377753SPeter Xu 	static volatile int index_ctr = 0;
244b4377753SPeter Xu 	int ctr;
245b4377753SPeter Xu 
2467f2477c2SPeter Xu 	assert(index_ctr < 65535);
247b4377753SPeter Xu 	ctr = atomic_inc_fetch(&index_ctr);
248b4377753SPeter Xu 	printf("INTR: alloc IRTE index %d\n", ctr);
249b4377753SPeter Xu 	return ctr;
2507f2477c2SPeter Xu }
2517f2477c2SPeter Xu 
2527f2477c2SPeter Xu static void vtd_setup_irte(struct pci_dev *dev, vtd_irte_t *irte,
253560586d9SPeter Xu 			   int vector, int dest_id, trigger_mode_t trigger)
2547f2477c2SPeter Xu {
2557f2477c2SPeter Xu 	assert(sizeof(vtd_irte_t) == 16);
2567f2477c2SPeter Xu 	memset(irte, 0, sizeof(*irte));
2577f2477c2SPeter Xu 	irte->fault_disable = 1;
2587f2477c2SPeter Xu 	irte->dest_mode = 0;	 /* physical */
259560586d9SPeter Xu 	irte->trigger_mode = trigger;
2607f2477c2SPeter Xu 	irte->delivery_mode = 0; /* fixed */
2617f2477c2SPeter Xu 	irte->irte_mode = 0;	 /* remapped */
2627f2477c2SPeter Xu 	irte->vector = vector;
2637f2477c2SPeter Xu 	irte->dest_id = dest_id;
2647f2477c2SPeter Xu 	irte->source_id = dev->bdf;
2657f2477c2SPeter Xu 	irte->sid_q = 0;
2667f2477c2SPeter Xu 	irte->sid_vtype = 1;     /* full-sid verify */
2677f2477c2SPeter Xu 	irte->present = 1;
2687f2477c2SPeter Xu }
2697f2477c2SPeter Xu 
2707f2477c2SPeter Xu struct vtd_msi_addr {
2717f2477c2SPeter Xu 	uint32_t __dont_care:2;
2727f2477c2SPeter Xu 	uint32_t handle_15:1;	 /* handle[15] */
2737f2477c2SPeter Xu 	uint32_t shv:1;
2747f2477c2SPeter Xu 	uint32_t interrupt_format:1;
2757f2477c2SPeter Xu 	uint32_t handle_0_14:15; /* handle[0:14] */
2767f2477c2SPeter Xu 	uint32_t head:12;	 /* 0xfee */
2777f2477c2SPeter Xu 	uint32_t addr_hi;	 /* not used except with x2apic */
2787f2477c2SPeter Xu } __attribute__ ((packed));
2797f2477c2SPeter Xu typedef struct vtd_msi_addr vtd_msi_addr_t;
2807f2477c2SPeter Xu 
2817f2477c2SPeter Xu struct vtd_msi_data {
2827f2477c2SPeter Xu 	uint16_t __reserved;
2837f2477c2SPeter Xu 	uint16_t subhandle;
2847f2477c2SPeter Xu } __attribute__ ((packed));
2857f2477c2SPeter Xu typedef struct vtd_msi_data vtd_msi_data_t;
2867f2477c2SPeter Xu 
287*3223ade2SPeter Xu struct vtd_ioapic_entry {
288*3223ade2SPeter Xu 	uint64_t vector:8;
289*3223ade2SPeter Xu 	uint64_t __zeros:3;
290*3223ade2SPeter Xu 	uint64_t index_15:1;
291*3223ade2SPeter Xu 	uint64_t delivery_status:1;
292*3223ade2SPeter Xu 	uint64_t polarity:1;
293*3223ade2SPeter Xu 	uint64_t remote_irr:1;
294*3223ade2SPeter Xu 	uint64_t trigger_mode:1;
295*3223ade2SPeter Xu 	uint64_t mask:1;
296*3223ade2SPeter Xu 	uint64_t __zeros_2:31;
297*3223ade2SPeter Xu 	uint64_t interrupt_format:1;
298*3223ade2SPeter Xu 	uint64_t index_0_14:15;
299*3223ade2SPeter Xu } __attribute__ ((packed));
300*3223ade2SPeter Xu typedef struct vtd_ioapic_entry vtd_ioapic_entry_t;
301*3223ade2SPeter Xu 
3027f2477c2SPeter Xu /**
3037f2477c2SPeter Xu  * vtd_setup_msi - setup MSI message for a device
3047f2477c2SPeter Xu  *
3057f2477c2SPeter Xu  * @dev: PCI device to setup MSI
3067f2477c2SPeter Xu  * @vector: interrupt vector
3077f2477c2SPeter Xu  * @dest_id: destination processor
3087f2477c2SPeter Xu  */
3097f2477c2SPeter Xu bool vtd_setup_msi(struct pci_dev *dev, int vector, int dest_id)
3107f2477c2SPeter Xu {
3117f2477c2SPeter Xu 	vtd_msi_data_t msi_data = {};
3127f2477c2SPeter Xu 	vtd_msi_addr_t msi_addr = {};
3137f2477c2SPeter Xu 	vtd_irte_t *irte = phys_to_virt(vtd_ir_table());
3147f2477c2SPeter Xu 	uint16_t index = vtd_intr_index_alloc();
3157f2477c2SPeter Xu 
3167f2477c2SPeter Xu 	assert(sizeof(vtd_msi_addr_t) == 8);
3177f2477c2SPeter Xu 	assert(sizeof(vtd_msi_data_t) == 4);
3187f2477c2SPeter Xu 
319560586d9SPeter Xu 	/* Use edge irq as default */
320560586d9SPeter Xu 	vtd_setup_irte(dev, irte + index, vector,
321560586d9SPeter Xu 		       dest_id, TRIGGER_EDGE);
3227f2477c2SPeter Xu 
3237f2477c2SPeter Xu 	msi_addr.handle_15 = index >> 15 & 1;
3247f2477c2SPeter Xu 	msi_addr.shv = 0;
3257f2477c2SPeter Xu 	msi_addr.interrupt_format = 1;
3267f2477c2SPeter Xu 	msi_addr.handle_0_14 = index & 0x7fff;
3277f2477c2SPeter Xu 	msi_addr.head = 0xfee;
3287f2477c2SPeter Xu 	msi_data.subhandle = 0;
3297f2477c2SPeter Xu 
3307f2477c2SPeter Xu 	return pci_setup_msi(dev, *(uint64_t *)&msi_addr,
3317f2477c2SPeter Xu 			     *(uint32_t *)&msi_data);
3327f2477c2SPeter Xu }
3337f2477c2SPeter Xu 
334*3223ade2SPeter Xu void vtd_setup_ioapic_irq(struct pci_dev *dev, int vector,
335*3223ade2SPeter Xu 			  int dest_id, trigger_mode_t trigger)
336*3223ade2SPeter Xu {
337*3223ade2SPeter Xu 	vtd_ioapic_entry_t entry = {};
338*3223ade2SPeter Xu 	vtd_irte_t *irte = phys_to_virt(vtd_ir_table());
339*3223ade2SPeter Xu 	ioapic_redir_entry_t *entry_2 = (ioapic_redir_entry_t *)&entry;
340*3223ade2SPeter Xu 	uint16_t index = vtd_intr_index_alloc();
341*3223ade2SPeter Xu 	uint8_t line;
342*3223ade2SPeter Xu 
343*3223ade2SPeter Xu 	assert(dev);
344*3223ade2SPeter Xu 	assert(sizeof(vtd_ioapic_entry_t) == 8);
345*3223ade2SPeter Xu 
346*3223ade2SPeter Xu 	vtd_setup_irte(dev, irte + index, vector,
347*3223ade2SPeter Xu 		       dest_id, trigger);
348*3223ade2SPeter Xu 
349*3223ade2SPeter Xu 	entry.vector = vector;
350*3223ade2SPeter Xu 	entry.trigger_mode = trigger;
351*3223ade2SPeter Xu 	entry.index_15 = (index >> 15) & 1;
352*3223ade2SPeter Xu 	entry.interrupt_format = 1;
353*3223ade2SPeter Xu 	entry.index_0_14 = index & 0x7fff;
354*3223ade2SPeter Xu 
355*3223ade2SPeter Xu 	line = pci_intx_line(dev);
356*3223ade2SPeter Xu 	ioapic_write_redir(line, *entry_2);
357*3223ade2SPeter Xu }
358*3223ade2SPeter Xu 
35916c0b05fSPeter Xu void vtd_init(void)
36016c0b05fSPeter Xu {
36116c0b05fSPeter Xu 	setup_vm();
36216c0b05fSPeter Xu 	smp_init();
36316c0b05fSPeter Xu 
36416c0b05fSPeter Xu 	vtd_reg_base = ioremap(Q35_HOST_BRIDGE_IOMMU_ADDR, PAGE_SIZE);
36516c0b05fSPeter Xu 
36616c0b05fSPeter Xu 	vtd_dump_init_info();
36716c0b05fSPeter Xu 	vtd_gcmd_or(VTD_GCMD_QI); /* Enable QI */
36816c0b05fSPeter Xu 	vtd_setup_root_table();
36916c0b05fSPeter Xu 	vtd_setup_ir_table();
37016c0b05fSPeter Xu 	vtd_gcmd_or(VTD_GCMD_DMAR); /* Enable DMAR */
37116c0b05fSPeter Xu 	vtd_gcmd_or(VTD_GCMD_IR);   /* Enable IR */
37216c0b05fSPeter Xu }
373