xref: /kvm-unit-tests/lib/x86/intel-iommu.c (revision 7fd49c4a8871a6424e3da4e4260a3cfbf7a9441b)
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"
17*5aca024eSPaolo Bonzini #include "alloc_page.h"
1892d2c192SPeter Xu 
1992d2c192SPeter Xu /*
2092d2c192SPeter Xu  * VT-d in QEMU currently only support 39 bits address width, which is
2192d2c192SPeter Xu  * 3-level translation.
2292d2c192SPeter Xu  */
2392d2c192SPeter Xu #define VTD_PAGE_LEVEL      3
2492d2c192SPeter Xu #define VTD_CE_AW_39BIT     0x1
2592d2c192SPeter Xu 
2692d2c192SPeter Xu typedef uint64_t vtd_pte_t;
2792d2c192SPeter Xu 
2892d2c192SPeter Xu struct vtd_root_entry {
2992d2c192SPeter Xu 	/* Quad 1 */
3092d2c192SPeter Xu 	uint64_t present:1;
3192d2c192SPeter Xu 	uint64_t __reserved:11;
3292d2c192SPeter Xu 	uint64_t context_table_p:52;
3392d2c192SPeter Xu 	/* Quad 2 */
3492d2c192SPeter Xu 	uint64_t __reserved_2;
3592d2c192SPeter Xu } __attribute__ ((packed));
3692d2c192SPeter Xu typedef struct vtd_root_entry vtd_re_t;
3792d2c192SPeter Xu 
3892d2c192SPeter Xu struct vtd_context_entry {
3992d2c192SPeter Xu 	/* Quad 1 */
4092d2c192SPeter Xu 	uint64_t present:1;
4192d2c192SPeter Xu 	uint64_t disable_fault_report:1;
4292d2c192SPeter Xu 	uint64_t trans_type:2;
4392d2c192SPeter Xu 	uint64_t __reserved:8;
4492d2c192SPeter Xu 	uint64_t slptptr:52;
4592d2c192SPeter Xu 	/* Quad 2 */
4692d2c192SPeter Xu 	uint64_t addr_width:3;
4792d2c192SPeter Xu 	uint64_t __ignore:4;
4892d2c192SPeter Xu 	uint64_t __reserved_2:1;
4992d2c192SPeter Xu 	uint64_t domain_id:16;
5092d2c192SPeter Xu 	uint64_t __reserved_3:40;
5192d2c192SPeter Xu } __attribute__ ((packed));
5292d2c192SPeter Xu typedef struct vtd_context_entry vtd_ce_t;
5316c0b05fSPeter Xu 
547f2477c2SPeter Xu struct vtd_irte {
557f2477c2SPeter Xu 	uint32_t present:1;
567f2477c2SPeter Xu 	uint32_t fault_disable:1;    /* Fault Processing Disable */
577f2477c2SPeter Xu 	uint32_t dest_mode:1;        /* Destination Mode */
587f2477c2SPeter Xu 	uint32_t redir_hint:1;       /* Redirection Hint */
597f2477c2SPeter Xu 	uint32_t trigger_mode:1;     /* Trigger Mode */
607f2477c2SPeter Xu 	uint32_t delivery_mode:3;    /* Delivery Mode */
617f2477c2SPeter Xu 	uint32_t __avail:4;          /* Available spaces for software */
627f2477c2SPeter Xu 	uint32_t __reserved_0:3;     /* Reserved 0 */
637f2477c2SPeter Xu 	uint32_t irte_mode:1;        /* IRTE Mode */
647f2477c2SPeter Xu 	uint32_t vector:8;           /* Interrupt Vector */
657f2477c2SPeter Xu 	uint32_t __reserved_1:8;     /* Reserved 1 */
667f2477c2SPeter Xu 	uint32_t dest_id;            /* Destination ID */
677f2477c2SPeter Xu 	uint16_t source_id:16;       /* Source-ID */
687f2477c2SPeter Xu 	uint64_t sid_q:2;            /* Source-ID Qualifier */
697f2477c2SPeter Xu 	uint64_t sid_vtype:2;        /* Source-ID Validation Type */
707f2477c2SPeter Xu 	uint64_t __reserved_2:44;    /* Reserved 2 */
717f2477c2SPeter Xu } __attribute__ ((packed));
727f2477c2SPeter Xu typedef struct vtd_irte vtd_irte_t;
737f2477c2SPeter Xu 
7416c0b05fSPeter Xu #define VTD_RTA_MASK  (PAGE_MASK)
7516c0b05fSPeter Xu #define VTD_IRTA_MASK (PAGE_MASK)
7616c0b05fSPeter Xu 
7716c0b05fSPeter Xu void *vtd_reg_base;
7816c0b05fSPeter Xu 
vtd_root_table(void)7916c0b05fSPeter Xu static uint64_t vtd_root_table(void)
8016c0b05fSPeter Xu {
8116c0b05fSPeter Xu 	/* No extend root table support yet */
8216c0b05fSPeter Xu 	return vtd_readq(DMAR_RTADDR_REG) & VTD_RTA_MASK;
8316c0b05fSPeter Xu }
8416c0b05fSPeter Xu 
vtd_ir_table(void)8516c0b05fSPeter Xu static uint64_t vtd_ir_table(void)
8616c0b05fSPeter Xu {
8716c0b05fSPeter Xu 	return vtd_readq(DMAR_IRTA_REG) & VTD_IRTA_MASK;
8816c0b05fSPeter Xu }
8916c0b05fSPeter Xu 
vtd_gcmd_or(uint32_t cmd)9016c0b05fSPeter Xu static void vtd_gcmd_or(uint32_t cmd)
9116c0b05fSPeter Xu {
9216c0b05fSPeter Xu 	uint32_t status;
9316c0b05fSPeter Xu 
9416c0b05fSPeter Xu 	/* We only allow set one bit for each time */
9516c0b05fSPeter Xu 	assert(is_power_of_2(cmd));
9616c0b05fSPeter Xu 
9716c0b05fSPeter Xu 	status = vtd_readl(DMAR_GSTS_REG);
9816c0b05fSPeter Xu 	vtd_writel(DMAR_GCMD_REG, status | cmd);
9916c0b05fSPeter Xu 
10016c0b05fSPeter Xu 	if (cmd & VTD_GCMD_ONE_SHOT_BITS) {
10116c0b05fSPeter Xu 		/* One-shot bits are taking effect immediately */
10216c0b05fSPeter Xu 		return;
10316c0b05fSPeter Xu 	}
10416c0b05fSPeter Xu 
10516c0b05fSPeter Xu 	/* Make sure IOMMU handled our command request */
10616c0b05fSPeter Xu 	while (!(vtd_readl(DMAR_GSTS_REG) & cmd))
10716c0b05fSPeter Xu 		cpu_relax();
10816c0b05fSPeter Xu }
10916c0b05fSPeter Xu 
vtd_dump_init_info(void)11016c0b05fSPeter Xu static void vtd_dump_init_info(void)
11116c0b05fSPeter Xu {
11216c0b05fSPeter Xu 	uint32_t version;
11316c0b05fSPeter Xu 
11416c0b05fSPeter Xu 	version = vtd_readl(DMAR_VER_REG);
11516c0b05fSPeter Xu 
11616c0b05fSPeter Xu 	/* Major version >= 1 */
11716c0b05fSPeter Xu 	assert(((version >> 3) & 0xf) >= 1);
11816c0b05fSPeter Xu 
119fd6aada0SRadim Krčmář 	printf("VT-d version:   %#x\n", version);
120fd6aada0SRadim Krčmář 	printf("     cap:       %#018lx\n", vtd_readq(DMAR_CAP_REG));
121fd6aada0SRadim Krčmář 	printf("     ecap:      %#018lx\n", vtd_readq(DMAR_ECAP_REG));
12216c0b05fSPeter Xu }
12316c0b05fSPeter Xu 
vtd_setup_root_table(void)12416c0b05fSPeter Xu static void vtd_setup_root_table(void)
12516c0b05fSPeter Xu {
12616c0b05fSPeter Xu 	void *root = alloc_page();
12716c0b05fSPeter Xu 
12816c0b05fSPeter Xu 	vtd_writeq(DMAR_RTADDR_REG, virt_to_phys(root));
12916c0b05fSPeter Xu 	vtd_gcmd_or(VTD_GCMD_ROOT);
130fd6aada0SRadim Krčmář 	printf("DMAR table address: %#018lx\n", vtd_root_table());
13116c0b05fSPeter Xu }
13216c0b05fSPeter Xu 
vtd_setup_ir_table(void)13316c0b05fSPeter Xu static void vtd_setup_ir_table(void)
13416c0b05fSPeter Xu {
13516c0b05fSPeter Xu 	void *root = alloc_page();
13616c0b05fSPeter Xu 
13716c0b05fSPeter Xu 	/* 0xf stands for table size (2^(0xf+1) == 65536) */
13816c0b05fSPeter Xu 	vtd_writeq(DMAR_IRTA_REG, virt_to_phys(root) | 0xf);
13916c0b05fSPeter Xu 	vtd_gcmd_or(VTD_GCMD_IR_TABLE);
140fd6aada0SRadim Krčmář 	printf("IR table address: %#018lx\n", vtd_ir_table());
14116c0b05fSPeter Xu }
14216c0b05fSPeter Xu 
vtd_install_pte(vtd_pte_t * root,iova_t iova,phys_addr_t pa,int level_target)14392d2c192SPeter Xu static void vtd_install_pte(vtd_pte_t *root, iova_t iova,
14492d2c192SPeter Xu 			    phys_addr_t pa, int level_target)
14592d2c192SPeter Xu {
14692d2c192SPeter Xu 	int level;
14792d2c192SPeter Xu 	unsigned int offset;
14892d2c192SPeter Xu 	void *page;
14992d2c192SPeter Xu 
15092d2c192SPeter Xu 	for (level = VTD_PAGE_LEVEL; level > level_target; level--) {
15192d2c192SPeter Xu 		offset = PGDIR_OFFSET(iova, level);
15292d2c192SPeter Xu 		if (!(root[offset] & VTD_PTE_RW)) {
15392d2c192SPeter Xu 			page = alloc_page();
15492d2c192SPeter Xu 			root[offset] = virt_to_phys(page) | VTD_PTE_RW;
15592d2c192SPeter Xu 		}
15692d2c192SPeter Xu 		root = (uint64_t *)(phys_to_virt(root[offset] &
15792d2c192SPeter Xu 						 VTD_PTE_ADDR));
15892d2c192SPeter Xu 	}
15992d2c192SPeter Xu 
16092d2c192SPeter Xu 	offset = PGDIR_OFFSET(iova, level);
16192d2c192SPeter Xu 	root[offset] = pa | VTD_PTE_RW;
16292d2c192SPeter Xu 	if (level != 1) {
16392d2c192SPeter Xu 		/* This is huge page */
16492d2c192SPeter Xu 		root[offset] |= VTD_PTE_HUGE;
16592d2c192SPeter Xu 	}
16692d2c192SPeter Xu }
16792d2c192SPeter Xu 
16892d2c192SPeter Xu /**
16992d2c192SPeter Xu  * vtd_map_range: setup IO address mapping for specific memory range
17092d2c192SPeter Xu  *
17192d2c192SPeter Xu  * @sid: source ID of the device to setup
17292d2c192SPeter Xu  * @iova: start IO virtual address
17392d2c192SPeter Xu  * @pa: start physical address
17492d2c192SPeter Xu  * @size: size of the mapping area
17592d2c192SPeter Xu  */
vtd_map_range(uint16_t sid,iova_t iova,phys_addr_t pa,size_t size)17692d2c192SPeter Xu void vtd_map_range(uint16_t sid, iova_t iova, phys_addr_t pa, size_t size)
17792d2c192SPeter Xu {
17892d2c192SPeter Xu 	uint8_t bus_n, devfn;
17992d2c192SPeter Xu 	void *slptptr;
18092d2c192SPeter Xu 	vtd_ce_t *ce;
18192d2c192SPeter Xu 	vtd_re_t *re = phys_to_virt(vtd_root_table());
18292d2c192SPeter Xu 
18392d2c192SPeter Xu 	assert(IS_ALIGNED(iova, SZ_4K));
18492d2c192SPeter Xu 	assert(IS_ALIGNED(pa, SZ_4K));
18592d2c192SPeter Xu 	assert(IS_ALIGNED(size, SZ_4K));
18692d2c192SPeter Xu 
18792d2c192SPeter Xu 	bus_n = PCI_BDF_GET_BUS(sid);
18892d2c192SPeter Xu 	devfn = PCI_BDF_GET_DEVFN(sid);
18992d2c192SPeter Xu 
19092d2c192SPeter Xu 	/* Point to the correct root entry */
19192d2c192SPeter Xu 	re += bus_n;
19292d2c192SPeter Xu 
19392d2c192SPeter Xu 	if (!re->present) {
19492d2c192SPeter Xu 		ce = alloc_page();
19592d2c192SPeter Xu 		memset(re, 0, sizeof(*re));
19692d2c192SPeter Xu 		re->context_table_p = virt_to_phys(ce) >> VTD_PAGE_SHIFT;
19792d2c192SPeter Xu 		re->present = 1;
19892d2c192SPeter Xu 		printf("allocated vt-d root entry for PCI bus %d\n",
19992d2c192SPeter Xu 		       bus_n);
20092d2c192SPeter Xu 	} else
201386d4498SAlexander Gordeev 		ce = phys_to_virt(re->context_table_p << VTD_PAGE_SHIFT);
20292d2c192SPeter Xu 
20392d2c192SPeter Xu 	/* Point to the correct context entry */
20492d2c192SPeter Xu 	ce += devfn;
20592d2c192SPeter Xu 
20692d2c192SPeter Xu 	if (!ce->present) {
20792d2c192SPeter Xu 		slptptr = alloc_page();
20892d2c192SPeter Xu 		memset(ce, 0, sizeof(*ce));
20992d2c192SPeter Xu 		/* To make it simple, domain ID is the same as SID */
21092d2c192SPeter Xu 		ce->domain_id = sid;
21192d2c192SPeter Xu 		/* We only test 39 bits width case (3-level paging) */
21292d2c192SPeter Xu 		ce->addr_width = VTD_CE_AW_39BIT;
21392d2c192SPeter Xu 		ce->slptptr = virt_to_phys(slptptr) >> VTD_PAGE_SHIFT;
21492d2c192SPeter Xu 		ce->trans_type = VTD_CONTEXT_TT_MULTI_LEVEL;
21592d2c192SPeter Xu 		ce->present = 1;
21692d2c192SPeter Xu 		/* No error reporting yet */
21792d2c192SPeter Xu 		ce->disable_fault_report = 1;
218fd6aada0SRadim Krčmář 		printf("allocated vt-d context entry for devfn %#x\n",
21992d2c192SPeter Xu 		       devfn);
22092d2c192SPeter Xu 	} else
221386d4498SAlexander Gordeev 		slptptr = phys_to_virt(ce->slptptr << VTD_PAGE_SHIFT);
22292d2c192SPeter Xu 
22392d2c192SPeter Xu 	while (size) {
22492d2c192SPeter Xu 		/* TODO: currently we only map 4K pages (level = 1) */
225fd6aada0SRadim Krčmář 		printf("map 4K page IOVA %#lx to %#lx (sid=%#06x)\n",
22692d2c192SPeter Xu 		       iova, pa, sid);
22792d2c192SPeter Xu 		vtd_install_pte(slptptr, iova, pa, 1);
22892d2c192SPeter Xu 		size -= VTD_PAGE_SIZE;
22992d2c192SPeter Xu 		iova += VTD_PAGE_SIZE;
23092d2c192SPeter Xu 		pa += VTD_PAGE_SIZE;
23192d2c192SPeter Xu 	}
23292d2c192SPeter Xu }
23392d2c192SPeter Xu 
vtd_intr_index_alloc(void)2347f2477c2SPeter Xu static uint16_t vtd_intr_index_alloc(void)
2357f2477c2SPeter Xu {
236b4377753SPeter Xu 	static volatile int index_ctr = 0;
237b4377753SPeter Xu 	int ctr;
238b4377753SPeter Xu 
2397f2477c2SPeter Xu 	assert(index_ctr < 65535);
240b4377753SPeter Xu 	ctr = atomic_inc_fetch(&index_ctr);
241b4377753SPeter Xu 	printf("INTR: alloc IRTE index %d\n", ctr);
242b4377753SPeter Xu 	return ctr;
2437f2477c2SPeter Xu }
2447f2477c2SPeter Xu 
vtd_setup_irte(struct pci_dev * dev,vtd_irte_t * irte,int vector,int dest_id,trigger_mode_t trigger)2457f2477c2SPeter Xu static void vtd_setup_irte(struct pci_dev *dev, vtd_irte_t *irte,
246560586d9SPeter Xu 			   int vector, int dest_id, trigger_mode_t trigger)
2477f2477c2SPeter Xu {
2487f2477c2SPeter Xu 	assert(sizeof(vtd_irte_t) == 16);
2497f2477c2SPeter Xu 	memset(irte, 0, sizeof(*irte));
2507f2477c2SPeter Xu 	irte->fault_disable = 1;
2517f2477c2SPeter Xu 	irte->dest_mode = 0;	 /* physical */
252560586d9SPeter Xu 	irte->trigger_mode = trigger;
2537f2477c2SPeter Xu 	irte->delivery_mode = 0; /* fixed */
2547f2477c2SPeter Xu 	irte->irte_mode = 0;	 /* remapped */
2557f2477c2SPeter Xu 	irte->vector = vector;
2567f2477c2SPeter Xu 	irte->dest_id = dest_id;
2577f2477c2SPeter Xu 	irte->source_id = dev->bdf;
2587f2477c2SPeter Xu 	irte->sid_q = 0;
2597f2477c2SPeter Xu 	irte->sid_vtype = 1;     /* full-sid verify */
2607f2477c2SPeter Xu 	irte->present = 1;
2617f2477c2SPeter Xu }
2627f2477c2SPeter Xu 
2637f2477c2SPeter Xu struct vtd_msi_addr {
2647f2477c2SPeter Xu 	uint32_t __dont_care:2;
2657f2477c2SPeter Xu 	uint32_t handle_15:1;	 /* handle[15] */
2667f2477c2SPeter Xu 	uint32_t shv:1;
2677f2477c2SPeter Xu 	uint32_t interrupt_format:1;
2687f2477c2SPeter Xu 	uint32_t handle_0_14:15; /* handle[0:14] */
2697f2477c2SPeter Xu 	uint32_t head:12;	 /* 0xfee */
2707f2477c2SPeter Xu 	uint32_t addr_hi;	 /* not used except with x2apic */
2717f2477c2SPeter Xu } __attribute__ ((packed));
2727f2477c2SPeter Xu typedef struct vtd_msi_addr vtd_msi_addr_t;
2737f2477c2SPeter Xu 
2747f2477c2SPeter Xu struct vtd_msi_data {
2757f2477c2SPeter Xu 	uint16_t __reserved;
2767f2477c2SPeter Xu 	uint16_t subhandle;
2777f2477c2SPeter Xu } __attribute__ ((packed));
2787f2477c2SPeter Xu typedef struct vtd_msi_data vtd_msi_data_t;
2797f2477c2SPeter Xu 
2803223ade2SPeter Xu struct vtd_ioapic_entry {
2813223ade2SPeter Xu 	uint64_t vector:8;
2823223ade2SPeter Xu 	uint64_t __zeros:3;
2833223ade2SPeter Xu 	uint64_t index_15:1;
2843223ade2SPeter Xu 	uint64_t delivery_status:1;
2853223ade2SPeter Xu 	uint64_t polarity:1;
2863223ade2SPeter Xu 	uint64_t remote_irr:1;
2873223ade2SPeter Xu 	uint64_t trigger_mode:1;
2883223ade2SPeter Xu 	uint64_t mask:1;
2893223ade2SPeter Xu 	uint64_t __zeros_2:31;
2903223ade2SPeter Xu 	uint64_t interrupt_format:1;
2913223ade2SPeter Xu 	uint64_t index_0_14:15;
2923223ade2SPeter Xu } __attribute__ ((packed));
2933223ade2SPeter Xu typedef struct vtd_ioapic_entry vtd_ioapic_entry_t;
2943223ade2SPeter Xu 
2957f2477c2SPeter Xu /**
2967f2477c2SPeter Xu  * vtd_setup_msi - setup MSI message for a device
2977f2477c2SPeter Xu  *
2987f2477c2SPeter Xu  * @dev: PCI device to setup MSI
2997f2477c2SPeter Xu  * @vector: interrupt vector
3007f2477c2SPeter Xu  * @dest_id: destination processor
3017f2477c2SPeter Xu  */
vtd_setup_msi(struct pci_dev * dev,int vector,int dest_id)3027f2477c2SPeter Xu bool vtd_setup_msi(struct pci_dev *dev, int vector, int dest_id)
3037f2477c2SPeter Xu {
3047f2477c2SPeter Xu 	vtd_msi_data_t msi_data = {};
3057f2477c2SPeter Xu 	vtd_msi_addr_t msi_addr = {};
3067f2477c2SPeter Xu 	vtd_irte_t *irte = phys_to_virt(vtd_ir_table());
3077f2477c2SPeter Xu 	uint16_t index = vtd_intr_index_alloc();
3087f2477c2SPeter Xu 
3097f2477c2SPeter Xu 	assert(sizeof(vtd_msi_addr_t) == 8);
3107f2477c2SPeter Xu 	assert(sizeof(vtd_msi_data_t) == 4);
3117f2477c2SPeter Xu 
312560586d9SPeter Xu 	/* Use edge irq as default */
313560586d9SPeter Xu 	vtd_setup_irte(dev, irte + index, vector,
314560586d9SPeter Xu 		       dest_id, TRIGGER_EDGE);
3157f2477c2SPeter Xu 
3167f2477c2SPeter Xu 	msi_addr.handle_15 = index >> 15 & 1;
3177f2477c2SPeter Xu 	msi_addr.shv = 0;
3187f2477c2SPeter Xu 	msi_addr.interrupt_format = 1;
3197f2477c2SPeter Xu 	msi_addr.handle_0_14 = index & 0x7fff;
3207f2477c2SPeter Xu 	msi_addr.head = 0xfee;
3217f2477c2SPeter Xu 	msi_data.subhandle = 0;
3227f2477c2SPeter Xu 
323fd6aada0SRadim Krčmář 	printf("%s: msi_addr=%#" PRIx64 ", msi_data=%#x\n", __func__,
32482f2f21aSAndrew Jones 		*(uint64_t *)&msi_addr, *(uint32_t *)&msi_data);
32582f2f21aSAndrew Jones 
3267f2477c2SPeter Xu 	return pci_setup_msi(dev, *(uint64_t *)&msi_addr,
3277f2477c2SPeter Xu 			     *(uint32_t *)&msi_data);
3287f2477c2SPeter Xu }
3297f2477c2SPeter Xu 
vtd_setup_ioapic_irq(struct pci_dev * dev,int vector,int dest_id,trigger_mode_t trigger)3303223ade2SPeter Xu void vtd_setup_ioapic_irq(struct pci_dev *dev, int vector,
3313223ade2SPeter Xu 			  int dest_id, trigger_mode_t trigger)
3323223ade2SPeter Xu {
3333223ade2SPeter Xu 	vtd_ioapic_entry_t entry = {};
3343223ade2SPeter Xu 	vtd_irte_t *irte = phys_to_virt(vtd_ir_table());
3353223ade2SPeter Xu 	ioapic_redir_entry_t *entry_2 = (ioapic_redir_entry_t *)&entry;
3363223ade2SPeter Xu 	uint16_t index = vtd_intr_index_alloc();
3373223ade2SPeter Xu 	uint8_t line;
3383223ade2SPeter Xu 
3393223ade2SPeter Xu 	assert(dev);
3403223ade2SPeter Xu 	assert(sizeof(vtd_ioapic_entry_t) == 8);
3413223ade2SPeter Xu 
3423223ade2SPeter Xu 	vtd_setup_irte(dev, irte + index, vector,
3433223ade2SPeter Xu 		       dest_id, trigger);
3443223ade2SPeter Xu 
3453223ade2SPeter Xu 	entry.vector = vector;
3463223ade2SPeter Xu 	entry.trigger_mode = trigger;
3473223ade2SPeter Xu 	entry.index_15 = (index >> 15) & 1;
3483223ade2SPeter Xu 	entry.interrupt_format = 1;
3493223ade2SPeter Xu 	entry.index_0_14 = index & 0x7fff;
3503223ade2SPeter Xu 
3513223ade2SPeter Xu 	line = pci_intx_line(dev);
3523223ade2SPeter Xu 	ioapic_write_redir(line, *entry_2);
3533223ade2SPeter Xu }
3543223ade2SPeter Xu 
vtd_init(void)35516c0b05fSPeter Xu void vtd_init(void)
35616c0b05fSPeter Xu {
35716c0b05fSPeter Xu 	vtd_reg_base = ioremap(Q35_HOST_BRIDGE_IOMMU_ADDR, PAGE_SIZE);
35816c0b05fSPeter Xu 
35916c0b05fSPeter Xu 	vtd_dump_init_info();
36016c0b05fSPeter Xu 	vtd_gcmd_or(VTD_GCMD_QI); /* Enable QI */
36116c0b05fSPeter Xu 	vtd_setup_root_table();
36216c0b05fSPeter Xu 	vtd_setup_ir_table();
36316c0b05fSPeter Xu 	vtd_gcmd_or(VTD_GCMD_DMAR); /* Enable DMAR */
36416c0b05fSPeter Xu 	vtd_gcmd_or(VTD_GCMD_IR);   /* Enable IR */
36516c0b05fSPeter Xu }
366