OSDN Git Service

PCI: keystone: Fix link training retries initiation
[sagit-ice-cold/kernel_xiaomi_msm8998.git] / drivers / xen / xlate_mmu.c
1 /*
2  * MMU operations common to all auto-translated physmap guests.
3  *
4  * Copyright (C) 2015 Citrix Systems R&D Ltd.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License version 2
8  * as published by the Free Software Foundation; or, when distributed
9  * separately from the Linux kernel or incorporated into other
10  * software packages, subject to the following license:
11  *
12  * Permission is hereby granted, free of charge, to any person obtaining a copy
13  * of this source file (the "Software"), to deal in the Software without
14  * restriction, including without limitation the rights to use, copy, modify,
15  * merge, publish, distribute, sublicense, and/or sell copies of the Software,
16  * and to permit persons to whom the Software is furnished to do so, subject to
17  * the following conditions:
18  *
19  * The above copyright notice and this permission notice shall be included in
20  * all copies or substantial portions of the Software.
21  *
22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
28  * IN THE SOFTWARE.
29  */
30 #include <linux/kernel.h>
31 #include <linux/mm.h>
32
33 #include <asm/xen/hypercall.h>
34 #include <asm/xen/hypervisor.h>
35
36 #include <xen/xen.h>
37 #include <xen/xen-ops.h>
38 #include <xen/page.h>
39 #include <xen/interface/xen.h>
40 #include <xen/interface/memory.h>
41
42 typedef void (*xen_gfn_fn_t)(unsigned long gfn, void *data);
43
44 /* Break down the pages in 4KB chunk and call fn for each gfn */
45 static void xen_for_each_gfn(struct page **pages, unsigned nr_gfn,
46                              xen_gfn_fn_t fn, void *data)
47 {
48         unsigned long xen_pfn = 0;
49         struct page *page;
50         int i;
51
52         for (i = 0; i < nr_gfn; i++) {
53                 if ((i % XEN_PFN_PER_PAGE) == 0) {
54                         page = pages[i / XEN_PFN_PER_PAGE];
55                         xen_pfn = page_to_xen_pfn(page);
56                 }
57                 fn(pfn_to_gfn(xen_pfn++), data);
58         }
59 }
60
61 struct remap_data {
62         xen_pfn_t *fgfn; /* foreign domain's gfn */
63         int nr_fgfn; /* Number of foreign gfn left to map */
64         pgprot_t prot;
65         domid_t  domid;
66         struct vm_area_struct *vma;
67         int index;
68         struct page **pages;
69         struct xen_remap_gfn_info *info;
70         int *err_ptr;
71         int mapped;
72
73         /* Hypercall parameters */
74         int h_errs[XEN_PFN_PER_PAGE];
75         xen_ulong_t h_idxs[XEN_PFN_PER_PAGE];
76         xen_pfn_t h_gpfns[XEN_PFN_PER_PAGE];
77
78         int h_iter;     /* Iterator */
79 };
80
81 static void setup_hparams(unsigned long gfn, void *data)
82 {
83         struct remap_data *info = data;
84
85         info->h_idxs[info->h_iter] = *info->fgfn;
86         info->h_gpfns[info->h_iter] = gfn;
87         info->h_errs[info->h_iter] = 0;
88
89         info->h_iter++;
90         info->fgfn++;
91 }
92
93 static int remap_pte_fn(pte_t *ptep, pgtable_t token, unsigned long addr,
94                         void *data)
95 {
96         struct remap_data *info = data;
97         struct page *page = info->pages[info->index++];
98         pte_t pte = pte_mkspecial(pfn_pte(page_to_pfn(page), info->prot));
99         int rc, nr_gfn;
100         uint32_t i;
101         struct xen_add_to_physmap_range xatp = {
102                 .domid = DOMID_SELF,
103                 .foreign_domid = info->domid,
104                 .space = XENMAPSPACE_gmfn_foreign,
105         };
106
107         nr_gfn = min_t(typeof(info->nr_fgfn), XEN_PFN_PER_PAGE, info->nr_fgfn);
108         info->nr_fgfn -= nr_gfn;
109
110         info->h_iter = 0;
111         xen_for_each_gfn(&page, nr_gfn, setup_hparams, info);
112         BUG_ON(info->h_iter != nr_gfn);
113
114         set_xen_guest_handle(xatp.idxs, info->h_idxs);
115         set_xen_guest_handle(xatp.gpfns, info->h_gpfns);
116         set_xen_guest_handle(xatp.errs, info->h_errs);
117         xatp.size = nr_gfn;
118
119         rc = HYPERVISOR_memory_op(XENMEM_add_to_physmap_range, &xatp);
120
121         /* info->err_ptr expect to have one error status per Xen PFN */
122         for (i = 0; i < nr_gfn; i++) {
123                 int err = (rc < 0) ? rc : info->h_errs[i];
124
125                 *(info->err_ptr++) = err;
126                 if (!err)
127                         info->mapped++;
128         }
129
130         /*
131          * Note: The hypercall will return 0 in most of the case if even if
132          * all the fgmfn are not mapped. We still have to update the pte
133          * as the userspace may decide to continue.
134          */
135         if (!rc)
136                 set_pte_at(info->vma->vm_mm, addr, ptep, pte);
137
138         return 0;
139 }
140
141 int xen_xlate_remap_gfn_array(struct vm_area_struct *vma,
142                               unsigned long addr,
143                               xen_pfn_t *gfn, int nr,
144                               int *err_ptr, pgprot_t prot,
145                               unsigned domid,
146                               struct page **pages)
147 {
148         int err;
149         struct remap_data data;
150         unsigned long range = DIV_ROUND_UP(nr, XEN_PFN_PER_PAGE) << PAGE_SHIFT;
151
152         /* Kept here for the purpose of making sure code doesn't break
153            x86 PVOPS */
154         BUG_ON(!((vma->vm_flags & (VM_PFNMAP | VM_IO)) == (VM_PFNMAP | VM_IO)));
155
156         data.fgfn = gfn;
157         data.nr_fgfn = nr;
158         data.prot  = prot;
159         data.domid = domid;
160         data.vma   = vma;
161         data.pages = pages;
162         data.index = 0;
163         data.err_ptr = err_ptr;
164         data.mapped = 0;
165
166         err = apply_to_page_range(vma->vm_mm, addr, range,
167                                   remap_pte_fn, &data);
168         return err < 0 ? err : data.mapped;
169 }
170 EXPORT_SYMBOL_GPL(xen_xlate_remap_gfn_array);
171
172 static void unmap_gfn(unsigned long gfn, void *data)
173 {
174         struct xen_remove_from_physmap xrp;
175
176         xrp.domid = DOMID_SELF;
177         xrp.gpfn = gfn;
178         (void)HYPERVISOR_memory_op(XENMEM_remove_from_physmap, &xrp);
179 }
180
181 int xen_xlate_unmap_gfn_range(struct vm_area_struct *vma,
182                               int nr, struct page **pages)
183 {
184         xen_for_each_gfn(pages, nr, unmap_gfn, NULL);
185
186         return 0;
187 }
188 EXPORT_SYMBOL_GPL(xen_xlate_unmap_gfn_range);