Skip to content

Commit 1e245e7

Browse files
author
Vates Git Importer
committed
pv-iommu-support.patch
1 parent c825a2f commit 1e245e7

21 files changed

Lines changed: 602 additions & 12 deletions

File tree

arch/x86/include/asm/xen/hypercall.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
#include <xen/interface/xen.h>
5252
#include <xen/interface/sched.h>
5353
#include <xen/interface/physdev.h>
54+
#include <xen/interface/pv-iommu.h>
5455
#include <xen/interface/platform.h>
5556
#include <xen/interface/xen-mca.h>
5657

@@ -329,6 +330,12 @@ MULTI_fpu_taskswitch(struct multicall_entry *mcl, int set)
329330
trace_xen_mc_entry(mcl, 1);
330331
}
331332

333+
static inline int
334+
HYPERVISOR_iommu_op(void *uop, unsigned int count)
335+
{
336+
return _hypercall2(int, iommu_op, uop, count);
337+
}
338+
332339
static inline void
333340
MULTI_update_va_mapping(struct multicall_entry *mcl, unsigned long va,
334341
pte_t new_val, unsigned long flags)

arch/x86/kernel/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ obj-$(CONFIG_X86_64) += sys_x86_64.o
6060
obj-$(CONFIG_X86_ESPFIX64) += espfix_64.o
6161
obj-$(CONFIG_SYSFS) += ksysfs.o
6262
obj-y += bootflag.o e820.o
63-
obj-y += pci-dma.o quirks.o topology.o kdebugfs.o
63+
obj-y += pci-dma.o pci-dma-xen.o quirks.o topology.o kdebugfs.o
6464
obj-y += alternative.o i8253.o hw_breakpoint.o
6565
obj-y += tsc.o tsc_msr.o io_delay.o rtc.o
6666
obj-y += resource.o

arch/x86/kernel/pci-dma-xen.c

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
#include <linux/types.h>
2+
#include <linux/kthread.h>
3+
#include <asm/xen/hypercall.h>
4+
#include <xen/interface/memory.h>
5+
#include <xen/hvc-console.h>
6+
#include <asm/xen/page.h>
7+
8+
#include <xen/xen.h>
9+
10+
#define IOMMU_BATCH_SIZE 128
11+
12+
extern unsigned long max_pfn;
13+
dma_addr_t pv_iommu_1_to_1_offset;
14+
EXPORT_SYMBOL(pv_iommu_1_to_1_offset);
15+
16+
bool pv_iommu_1_to_1_setup_complete;
17+
EXPORT_SYMBOL(pv_iommu_1_to_1_setup_complete);
18+
19+
static struct pv_iommu_op iommu_ops[IOMMU_BATCH_SIZE];
20+
21+
int xen_iommu_map_page(unsigned long bfn, unsigned long mfn)
22+
{
23+
struct pv_iommu_op iommu_op;
24+
int rc;
25+
26+
iommu_op.u.map_page.bfn = bfn;
27+
iommu_op.u.map_page.gfn = mfn;
28+
iommu_op.flags = IOMMU_OP_readable | IOMMU_OP_writeable | IOMMU_MAP_OP_no_ref_cnt;
29+
iommu_op.subop_id = IOMMUOP_map_page;
30+
rc = HYPERVISOR_iommu_op(&iommu_op, 1);
31+
if (rc < 0) {
32+
printk("Failed to setup IOMMU mapping for gpfn 0x%lx, mfn 0x%lx, err %d\n",
33+
bfn, mfn, rc);
34+
return rc;
35+
}
36+
return iommu_op.status;
37+
}
38+
EXPORT_SYMBOL_GPL(xen_iommu_map_page);
39+
40+
int xen_iommu_unmap_page(unsigned long bfn)
41+
{
42+
struct pv_iommu_op iommu_op;
43+
int rc;
44+
45+
iommu_op.u.unmap_page.bfn = bfn;
46+
iommu_op.flags = IOMMU_MAP_OP_no_ref_cnt;
47+
iommu_op.subop_id = IOMMUOP_unmap_page;
48+
rc = HYPERVISOR_iommu_op(&iommu_op, 1);
49+
if (rc < 0) {
50+
printk("Failed to remove IOMMU mapping for gpfn 0x%lx, err %d\n", bfn, rc);
51+
return rc;
52+
}
53+
return iommu_op.status;
54+
}
55+
56+
int xen_iommu_batch(struct pv_iommu_op *iommu_ops, int count)
57+
{
58+
int rc;
59+
60+
rc = HYPERVISOR_iommu_op(iommu_ops, count);
61+
if (rc < 0) {
62+
printk("Failed to batch IOMMU map, err %d\n", rc);
63+
}
64+
return rc;
65+
}
66+
EXPORT_SYMBOL_GPL(xen_iommu_batch);
67+
68+
static int check_batch(int size)
69+
{
70+
int op;
71+
int res=0;
72+
for (op = 1; op < size; op +=2)
73+
{
74+
if ( iommu_ops[op].status ) {
75+
printk("Iommu op %d went wrong, subop id %d, bfn 0x%llx, gfn 0x%llx\n, err %d, flags 0x%x\n",
76+
op, iommu_ops[op].subop_id,
77+
iommu_ops[op].u.map_page.bfn,
78+
iommu_ops[op].u.map_page.gfn,
79+
iommu_ops[op].status, iommu_ops[op].flags );
80+
res++;
81+
}
82+
}
83+
return res;
84+
}
85+
86+
87+
void __init pci_xen_pv_iommu_late_init(void)
88+
{
89+
if (pv_iommu_1_to_1_offset) {
90+
/* Xen has already set up 1-1 mapping for us */
91+
pv_iommu_1_to_1_setup_complete = true;
92+
printk(KERN_INFO "XEN-PV-IOMMU - completed setting up 1-1 mapping\n");
93+
}
94+
}
95+
96+
/*
97+
* Detect is we can use PV-IOMMU
98+
* If we can, caller needs to disable xen_swiotlb.
99+
* and additionally set up normal x86 swiotlb. (PV-IOMMU is layered on top)
100+
* Otherwise keep xen_swiotlb & don't setup x86 one.
101+
*/
102+
103+
int pci_xen_swiotlb_pviommu_detect(void)
104+
{
105+
int count = 0;
106+
u64 pfn, pfn_limit, max_host_mfn = 0;
107+
struct pv_iommu_op_ext iommu_op;
108+
int rc;
109+
110+
if (!xen_initial_domain())
111+
return 0;
112+
113+
iommu_op.u.query_caps.offset = 0;
114+
iommu_op.flags = 0;
115+
iommu_op.status = 0;
116+
iommu_op.subop_id = IOMMUOP_query_caps;
117+
rc = HYPERVISOR_iommu_op(&iommu_op, 1);
118+
119+
if (rc || !(iommu_op.flags & IOMMU_QUERY_map_cap)) {
120+
printk(KERN_INFO "XEN-PV-IOMMU: No IOMMU cap.\n");
121+
return 0;
122+
}
123+
124+
max_host_mfn = HYPERVISOR_memory_op(XENMEM_maximum_ram_page, NULL);
125+
printk("Max host RAM MFN is 0x%llx\n",max_host_mfn);
126+
printk("max_pfn is 0x%lx\n",max_pfn);
127+
128+
/* Check and Setup 1-1 host RAM offset location */
129+
if (iommu_op.flags & IOMMU_QUERY_map_all_mfns)
130+
pv_iommu_1_to_1_offset = (dma_addr_t) iommu_op.u.query_caps.offset << PAGE_SHIFT;
131+
/* If offset is 0 or not set - disable PV IOMMU */
132+
if (!pv_iommu_1_to_1_offset) {
133+
printk(KERN_INFO "XEN-PV-IOMMU: Disabled.\n");
134+
return 0;
135+
}
136+
pfn_limit = pv_iommu_1_to_1_offset >> PAGE_SHIFT;
137+
if (max_pfn >= pfn_limit) {
138+
printk("XEN-PV-IOMMU: bfn_foreign_offset at %llu, is too small"
139+
" for Dom0. Needs %lu\n", pfn_limit, max_pfn + 1);
140+
BUG();
141+
}
142+
143+
pfn_limit = min(max_host_mfn, pfn_limit);
144+
145+
/* Setup 1-1 mapping of GPFN to MFN */
146+
for (pfn=0; pfn < pfn_limit; pfn++)
147+
{
148+
unsigned long mfn = get_phys_to_machine(pfn);
149+
if (mfn != INVALID_P2M_ENTRY && mfn != IDENTITY_FRAME(pfn))
150+
{
151+
iommu_ops[count].u.unmap_page.bfn = pfn;
152+
iommu_ops[count].flags = IOMMU_MAP_OP_no_ref_cnt;
153+
iommu_ops[count].subop_id = IOMMUOP_unmap_page;
154+
count++;
155+
iommu_ops[count].u.map_page.bfn = pfn;
156+
iommu_ops[count].u.map_page.gfn = pfn_to_mfn(pfn);
157+
iommu_ops[count].flags = IOMMU_OP_readable |
158+
IOMMU_OP_writeable |
159+
IOMMU_MAP_OP_no_ref_cnt;
160+
iommu_ops[count].subop_id = IOMMUOP_map_page;
161+
count++;
162+
}
163+
if (count == IOMMU_BATCH_SIZE)
164+
{
165+
count = 0;
166+
if (xen_iommu_batch(iommu_ops, IOMMU_BATCH_SIZE)
167+
|| check_batch(IOMMU_BATCH_SIZE)) {
168+
printk("Failed to fully Setup 1-1 mapping of GPFN to MFN.\n");
169+
BUG();
170+
}
171+
}
172+
}
173+
if (count) {
174+
if (xen_iommu_batch(iommu_ops, count)
175+
|| check_batch(count)) {
176+
printk("Failed to fully Setup 1-1 mapping of GPFN to MFN.\n");
177+
BUG();
178+
}
179+
}
180+
181+
printk("XEN-PV-IOMMU: Using GPFN IOMMU mode, 1-to-1 offset is 0x%llx\n",
182+
pv_iommu_1_to_1_offset);
183+
return 1;
184+
}

arch/x86/kernel/pci-dma.c

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
#include <xen/xen.h>
1919
#include <xen/swiotlb-xen.h>
2020

21+
void pci_xen_pv_iommu_late_init(void);
22+
int pci_xen_swiotlb_pviommu_detect(void);
23+
2124
static bool disable_dac_quirk __read_mostly;
2225

2326
const struct dma_map_ops *dma_ops;
@@ -83,9 +86,13 @@ static void __init pci_xen_swiotlb_init(void)
8386
if (!xen_swiotlb_enabled())
8487
return;
8588
x86_swiotlb_enable = true;
86-
x86_swiotlb_flags |= SWIOTLB_ANY;
89+
if (!pv_iommu_1_to_1_offset)
90+
x86_swiotlb_flags |= SWIOTLB_ANY;
91+
8792
swiotlb_init_remap(true, x86_swiotlb_flags, xen_swiotlb_fixup);
88-
dma_ops = &xen_swiotlb_dma_ops;
93+
94+
if (!pv_iommu_1_to_1_offset)
95+
dma_ops = &xen_swiotlb_dma_ops;
8996
if (IS_ENABLED(CONFIG_PCI))
9097
pci_request_acs();
9198
}
@@ -98,14 +105,20 @@ static inline void __init pci_xen_swiotlb_init(void)
98105
void __init pci_iommu_alloc(void)
99106
{
100107
if (xen_pv_domain()) {
108+
bool pviommu = pci_xen_swiotlb_pviommu_detect();
101109
pci_xen_swiotlb_init();
102-
return;
110+
if (!pviommu)
111+
return;
103112
}
104113
pci_swiotlb_detect();
105114
gart_iommu_hole_init();
106115
amd_iommu_detect();
107116
detect_intel_iommu();
108117
swiotlb_init(x86_swiotlb_enable, x86_swiotlb_flags);
118+
if (pv_iommu_1_to_1_offset) {
119+
printk(KERN_INFO "XEN-PV-IOMMU: "
120+
"Using software bounce buffering for IO on 32bit DMA devices (SWIOTLB)\n");
121+
}
109122
}
110123

111124
/*
@@ -180,6 +193,9 @@ static int __init pci_iommu_init(void)
180193
#ifdef CONFIG_SWIOTLB
181194
/* An IOMMU turned us off. */
182195
if (x86_swiotlb_enable) {
196+
/* if PV-IOMMU enabled, call late init too */
197+
pci_xen_pv_iommu_late_init();
198+
183199
pr_info("PCI-DMA: Using software bounce buffering for IO (SWIOTLB)\n");
184200
swiotlb_print_info();
185201
} else {

arch/x86/xen/xen-head.S

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,5 +181,6 @@ SYM_FUNC_END(xen_hypercall_intel)
181181
.long FEATURES_PV | FEATURES_PVH | FEATURES_DOM0)
182182
ELFNOTE(Xen, XEN_ELFNOTE_LOADER, .asciz "generic")
183183
ELFNOTE(Xen, XEN_ELFNOTE_SUSPEND_CANCEL, .long 1)
184+
ELFNOTE(XS, XS_ELFNOTE_PV_IOMMU, .long 1)
184185

185186
#endif /*CONFIG_XEN */

drivers/xen/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ obj-$(CONFIG_XENFS) += xenfs/
2424
obj-$(CONFIG_XEN_SYS_HYPERVISOR) += sys-hypervisor.o
2525
obj-$(CONFIG_XEN_PVHVM_GUEST) += platform-pci.o
2626
obj-$(CONFIG_SWIOTLB_XEN) += swiotlb-xen.o
27+
obj-$(CONFIG_SWIOTLB_XEN) += pv-iommu-xen.o
2728
obj-$(CONFIG_XEN_MCE_LOG) += mcelog.o
2829
obj-$(CONFIG_XEN_PCI_STUB) += xen-pciback/
2930
obj-$(CONFIG_XEN_PRIVCMD) += xen-privcmd.o

drivers/xen/balloon.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474
#include <xen/features.h>
7575
#include <xen/page.h>
7676
#include <xen/mem-reservation.h>
77+
#include <xen/swiotlb-xen.h>
7778

7879
#undef MODULE_PARAM_PREFIX
7980
#define MODULE_PARAM_PREFIX "xen."
@@ -344,6 +345,17 @@ static void xen_online_page(struct page *page, unsigned int order)
344345
struct page *p;
345346

346347
pr_debug("Online %lu pages starting at pfn 0x%lx\n", size, start_pfn);
348+
349+
#ifdef CONFIG_XEN_HAVE_PVMMU
350+
/*
351+
* Clear any existing IOMMU mappings of the BFN (== PFN) for
352+
* this page, so the correct IOMMU mapping can be created when
353+
* the page is returned.
354+
*/
355+
if (pv_iommu_1_to_1_offset)
356+
xen_iommu_unmap_page(page_to_pfn(page));
357+
#endif
358+
347359
mutex_lock(&balloon_mutex);
348360
for (i = 0; i < size; i++) {
349361
p = pfn_to_page(start_pfn + i);

drivers/xen/biomerge.c

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,24 @@
33
#include <linux/export.h>
44
#include <xen/xen.h>
55
#include <xen/page.h>
6+
#include <xen/swiotlb-xen.h>
67

78
/* check if @page can be merged with 'vec1' */
89
bool xen_biovec_phys_mergeable(const struct bio_vec *vec1,
910
const struct page *page)
1011
{
1112
#if XEN_PAGE_SIZE == PAGE_SIZE
12-
unsigned long bfn1 = pfn_to_bfn(page_to_pfn(vec1->bv_page));
13-
unsigned long bfn2 = pfn_to_bfn(page_to_pfn(page));
13+
unsigned long pfn1 = page_to_pfn(vec1->bv_page);
14+
unsigned long pfn2 = page_to_pfn(page);
15+
unsigned long bfn1, bfn2;
1416

17+
if (!pv_iommu_1_to_1_offset) {
18+
bfn1 = pfn_to_bfn(pfn1);
19+
bfn2 = pfn_to_bfn(pfn2);
20+
} else {
21+
bfn1 = pfn1;
22+
bfn2 = pfn2;
23+
}
1524
return bfn1 + PFN_DOWN(vec1->bv_offset + vec1->bv_len) == bfn2;
1625
#else
1726
/*

drivers/xen/ioemu.c

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,48 @@ int xen_ioemu_inject_msi(domid_t domid, uint64_t addr, uint32_t data)
8383

8484
return HYPERVISOR_dm_op(domid, 1, &op_buf);
8585
}
86+
87+
/**
88+
* xen_ioemu_map_foreign_gfn_to_bfn: Returns the BFN's corresponding to GFN's.
89+
* @pv_iommu_ops: pv_iommu_ops contains the struct_ map_foreign_page
90+
* that will be used for lookup for BFN.
91+
* @count: count of struct pv_iommu_ops.
92+
*
93+
* Its a wrapper function for getting BFN from GFN using IOMMU hypercall.
94+
*/
95+
int xen_ioemu_map_foreign_gfn_to_bfn(struct pv_iommu_op *ops, int count)
96+
{
97+
int i;
98+
int rc = 0;
99+
for (i = 0; i < count; i++)
100+
{
101+
ops[i].subop_id = IOMMUOP_lookup_foreign_page;
102+
ops[i].flags |= IOMMU_OP_writeable;
103+
}
104+
rc = HYPERVISOR_iommu_op(ops, count);
105+
return rc;
106+
}
107+
108+
/**
109+
* xen_ioemu_unmap_foreign_gfn_to_bfn: Unmap BFN's corresponding to GFN's.
110+
* @pv_iommu_ops: pv_iommu_ops contains the struct unmap_foreign_page
111+
* that will be used to unmap BFNs.
112+
* @count: count of struct pv_iommu_ops.
113+
*
114+
* Its a wrapper function to unmap foreign GFN's to BFN's .
115+
*/
116+
int xen_ioemu_unmap_foreign_gfn_to_bfn(struct pv_iommu_op *ops, int count)
117+
{
118+
int i;
119+
int rc = 0;
120+
for (i = 0; i < count; i++)
121+
{
122+
ops[i].subop_id = IOMMUOP_unmap_foreign_page;
123+
}
124+
rc = HYPERVISOR_iommu_op(ops, count);
125+
return rc;
126+
}
127+
86128
EXPORT_SYMBOL(xen_ioemu_inject_msi);
129+
EXPORT_SYMBOL(xen_ioemu_map_foreign_gfn_to_bfn);
130+
EXPORT_SYMBOL(xen_ioemu_unmap_foreign_gfn_to_bfn);

0 commit comments

Comments
 (0)