Merge commit 'v2.6.28-rc2' into core/locking
[sfrench/cifs-2.6.git] / arch / ia64 / xen / xcom_hcall.c
1 /*
2  * This program is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 2 of the License, or
5  * (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software
14  * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
15  *
16  *          Tristan Gingold <tristan.gingold@bull.net>
17  *
18  *          Copyright (c) 2007
19  *          Isaku Yamahata <yamahata at valinux co jp>
20  *                          VA Linux Systems Japan K.K.
21  *          consolidate mini and inline version.
22  */
23
24 #include <linux/module.h>
25 #include <xen/interface/xen.h>
26 #include <xen/interface/memory.h>
27 #include <xen/interface/grant_table.h>
28 #include <xen/interface/callback.h>
29 #include <xen/interface/vcpu.h>
30 #include <asm/xen/hypervisor.h>
31 #include <asm/xen/xencomm.h>
32
33 /* Xencomm notes:
34  * This file defines hypercalls to be used by xencomm.  The hypercalls simply
35  * create inlines or mini descriptors for pointers and then call the raw arch
36  * hypercall xencomm_arch_hypercall_XXX
37  *
38  * If the arch wants to directly use these hypercalls, simply define macros
39  * in asm/xen/hypercall.h, eg:
40  *  #define HYPERVISOR_sched_op xencomm_hypercall_sched_op
41  *
42  * The arch may also define HYPERVISOR_xxx as a function and do more operations
43  * before/after doing the hypercall.
44  *
45  * Note: because only inline or mini descriptors are created these functions
46  * must only be called with in kernel memory parameters.
47  */
48
49 int
50 xencomm_hypercall_console_io(int cmd, int count, char *str)
51 {
52         /* xen early printk uses console io hypercall before
53          * xencomm initialization. In that case, we just ignore it.
54          */
55         if (!xencomm_is_initialized())
56                 return 0;
57
58         return xencomm_arch_hypercall_console_io
59                 (cmd, count, xencomm_map_no_alloc(str, count));
60 }
61 EXPORT_SYMBOL_GPL(xencomm_hypercall_console_io);
62
63 int
64 xencomm_hypercall_event_channel_op(int cmd, void *op)
65 {
66         struct xencomm_handle *desc;
67         desc = xencomm_map_no_alloc(op, sizeof(struct evtchn_op));
68         if (desc == NULL)
69                 return -EINVAL;
70
71         return xencomm_arch_hypercall_event_channel_op(cmd, desc);
72 }
73 EXPORT_SYMBOL_GPL(xencomm_hypercall_event_channel_op);
74
75 int
76 xencomm_hypercall_xen_version(int cmd, void *arg)
77 {
78         struct xencomm_handle *desc;
79         unsigned int argsize;
80
81         switch (cmd) {
82         case XENVER_version:
83                 /* do not actually pass an argument */
84                 return xencomm_arch_hypercall_xen_version(cmd, 0);
85         case XENVER_extraversion:
86                 argsize = sizeof(struct xen_extraversion);
87                 break;
88         case XENVER_compile_info:
89                 argsize = sizeof(struct xen_compile_info);
90                 break;
91         case XENVER_capabilities:
92                 argsize = sizeof(struct xen_capabilities_info);
93                 break;
94         case XENVER_changeset:
95                 argsize = sizeof(struct xen_changeset_info);
96                 break;
97         case XENVER_platform_parameters:
98                 argsize = sizeof(struct xen_platform_parameters);
99                 break;
100         case XENVER_get_features:
101                 argsize = (arg == NULL) ? 0 : sizeof(struct xen_feature_info);
102                 break;
103
104         default:
105                 printk(KERN_DEBUG
106                        "%s: unknown version op %d\n", __func__, cmd);
107                 return -ENOSYS;
108         }
109
110         desc = xencomm_map_no_alloc(arg, argsize);
111         if (desc == NULL)
112                 return -EINVAL;
113
114         return xencomm_arch_hypercall_xen_version(cmd, desc);
115 }
116 EXPORT_SYMBOL_GPL(xencomm_hypercall_xen_version);
117
118 int
119 xencomm_hypercall_physdev_op(int cmd, void *op)
120 {
121         unsigned int argsize;
122
123         switch (cmd) {
124         case PHYSDEVOP_apic_read:
125         case PHYSDEVOP_apic_write:
126                 argsize = sizeof(struct physdev_apic);
127                 break;
128         case PHYSDEVOP_alloc_irq_vector:
129         case PHYSDEVOP_free_irq_vector:
130                 argsize = sizeof(struct physdev_irq);
131                 break;
132         case PHYSDEVOP_irq_status_query:
133                 argsize = sizeof(struct physdev_irq_status_query);
134                 break;
135
136         default:
137                 printk(KERN_DEBUG
138                        "%s: unknown physdev op %d\n", __func__, cmd);
139                 return -ENOSYS;
140         }
141
142         return xencomm_arch_hypercall_physdev_op
143                 (cmd, xencomm_map_no_alloc(op, argsize));
144 }
145
146 static int
147 xencommize_grant_table_op(struct xencomm_mini **xc_area,
148                           unsigned int cmd, void *op, unsigned int count,
149                           struct xencomm_handle **desc)
150 {
151         struct xencomm_handle *desc1;
152         unsigned int argsize;
153
154         switch (cmd) {
155         case GNTTABOP_map_grant_ref:
156                 argsize = sizeof(struct gnttab_map_grant_ref);
157                 break;
158         case GNTTABOP_unmap_grant_ref:
159                 argsize = sizeof(struct gnttab_unmap_grant_ref);
160                 break;
161         case GNTTABOP_setup_table:
162         {
163                 struct gnttab_setup_table *setup = op;
164
165                 argsize = sizeof(*setup);
166
167                 if (count != 1)
168                         return -EINVAL;
169                 desc1 = __xencomm_map_no_alloc
170                         (xen_guest_handle(setup->frame_list),
171                          setup->nr_frames *
172                          sizeof(*xen_guest_handle(setup->frame_list)),
173                          *xc_area);
174                 if (desc1 == NULL)
175                         return -EINVAL;
176                 (*xc_area)++;
177                 set_xen_guest_handle(setup->frame_list, (void *)desc1);
178                 break;
179         }
180         case GNTTABOP_dump_table:
181                 argsize = sizeof(struct gnttab_dump_table);
182                 break;
183         case GNTTABOP_transfer:
184                 argsize = sizeof(struct gnttab_transfer);
185                 break;
186         case GNTTABOP_copy:
187                 argsize = sizeof(struct gnttab_copy);
188                 break;
189         case GNTTABOP_query_size:
190                 argsize = sizeof(struct gnttab_query_size);
191                 break;
192         default:
193                 printk(KERN_DEBUG "%s: unknown hypercall grant table op %d\n",
194                        __func__, cmd);
195                 BUG();
196         }
197
198         *desc = __xencomm_map_no_alloc(op, count * argsize, *xc_area);
199         if (*desc == NULL)
200                 return -EINVAL;
201         (*xc_area)++;
202
203         return 0;
204 }
205
206 int
207 xencomm_hypercall_grant_table_op(unsigned int cmd, void *op,
208                                  unsigned int count)
209 {
210         int rc;
211         struct xencomm_handle *desc;
212         XENCOMM_MINI_ALIGNED(xc_area, 2);
213
214         rc = xencommize_grant_table_op(&xc_area, cmd, op, count, &desc);
215         if (rc)
216                 return rc;
217
218         return xencomm_arch_hypercall_grant_table_op(cmd, desc, count);
219 }
220 EXPORT_SYMBOL_GPL(xencomm_hypercall_grant_table_op);
221
222 int
223 xencomm_hypercall_sched_op(int cmd, void *arg)
224 {
225         struct xencomm_handle *desc;
226         unsigned int argsize;
227
228         switch (cmd) {
229         case SCHEDOP_yield:
230         case SCHEDOP_block:
231                 argsize = 0;
232                 break;
233         case SCHEDOP_shutdown:
234                 argsize = sizeof(struct sched_shutdown);
235                 break;
236         case SCHEDOP_poll:
237         {
238                 struct sched_poll *poll = arg;
239                 struct xencomm_handle *ports;
240
241                 argsize = sizeof(struct sched_poll);
242                 ports = xencomm_map_no_alloc(xen_guest_handle(poll->ports),
243                                      sizeof(*xen_guest_handle(poll->ports)));
244
245                 set_xen_guest_handle(poll->ports, (void *)ports);
246                 break;
247         }
248         default:
249                 printk(KERN_DEBUG "%s: unknown sched op %d\n", __func__, cmd);
250                 return -ENOSYS;
251         }
252
253         desc = xencomm_map_no_alloc(arg, argsize);
254         if (desc == NULL)
255                 return -EINVAL;
256
257         return xencomm_arch_hypercall_sched_op(cmd, desc);
258 }
259 EXPORT_SYMBOL_GPL(xencomm_hypercall_sched_op);
260
261 int
262 xencomm_hypercall_multicall(void *call_list, int nr_calls)
263 {
264         int rc;
265         int i;
266         struct multicall_entry *mce;
267         struct xencomm_handle *desc;
268         XENCOMM_MINI_ALIGNED(xc_area, nr_calls * 2);
269
270         for (i = 0; i < nr_calls; i++) {
271                 mce = (struct multicall_entry *)call_list + i;
272
273                 switch (mce->op) {
274                 case __HYPERVISOR_update_va_mapping:
275                 case __HYPERVISOR_mmu_update:
276                         /* No-op on ia64.  */
277                         break;
278                 case __HYPERVISOR_grant_table_op:
279                         rc = xencommize_grant_table_op
280                                 (&xc_area,
281                                  mce->args[0], (void *)mce->args[1],
282                                  mce->args[2], &desc);
283                         if (rc)
284                                 return rc;
285                         mce->args[1] = (unsigned long)desc;
286                         break;
287                 case __HYPERVISOR_memory_op:
288                 default:
289                         printk(KERN_DEBUG
290                                "%s: unhandled multicall op entry op %lu\n",
291                                __func__, mce->op);
292                         return -ENOSYS;
293                 }
294         }
295
296         desc = xencomm_map_no_alloc(call_list,
297                                     nr_calls * sizeof(struct multicall_entry));
298         if (desc == NULL)
299                 return -EINVAL;
300
301         return xencomm_arch_hypercall_multicall(desc, nr_calls);
302 }
303 EXPORT_SYMBOL_GPL(xencomm_hypercall_multicall);
304
305 int
306 xencomm_hypercall_callback_op(int cmd, void *arg)
307 {
308         unsigned int argsize;
309         switch (cmd) {
310         case CALLBACKOP_register:
311                 argsize = sizeof(struct callback_register);
312                 break;
313         case CALLBACKOP_unregister:
314                 argsize = sizeof(struct callback_unregister);
315                 break;
316         default:
317                 printk(KERN_DEBUG
318                        "%s: unknown callback op %d\n", __func__, cmd);
319                 return -ENOSYS;
320         }
321
322         return xencomm_arch_hypercall_callback_op
323                 (cmd, xencomm_map_no_alloc(arg, argsize));
324 }
325
326 static int
327 xencommize_memory_reservation(struct xencomm_mini *xc_area,
328                               struct xen_memory_reservation *mop)
329 {
330         struct xencomm_handle *desc;
331
332         desc = __xencomm_map_no_alloc(xen_guest_handle(mop->extent_start),
333                         mop->nr_extents *
334                         sizeof(*xen_guest_handle(mop->extent_start)),
335                         xc_area);
336         if (desc == NULL)
337                 return -EINVAL;
338
339         set_xen_guest_handle(mop->extent_start, (void *)desc);
340         return 0;
341 }
342
343 int
344 xencomm_hypercall_memory_op(unsigned int cmd, void *arg)
345 {
346         GUEST_HANDLE(xen_pfn_t) extent_start_va[2] = { {NULL}, {NULL} };
347         struct xen_memory_reservation *xmr = NULL;
348         int rc;
349         struct xencomm_handle *desc;
350         unsigned int argsize;
351         XENCOMM_MINI_ALIGNED(xc_area, 2);
352
353         switch (cmd) {
354         case XENMEM_increase_reservation:
355         case XENMEM_decrease_reservation:
356         case XENMEM_populate_physmap:
357                 xmr = (struct xen_memory_reservation *)arg;
358                 set_xen_guest_handle(extent_start_va[0],
359                                      xen_guest_handle(xmr->extent_start));
360
361                 argsize = sizeof(*xmr);
362                 rc = xencommize_memory_reservation(xc_area, xmr);
363                 if (rc)
364                         return rc;
365                 xc_area++;
366                 break;
367
368         case XENMEM_maximum_ram_page:
369                 argsize = 0;
370                 break;
371
372         case XENMEM_add_to_physmap:
373                 argsize = sizeof(struct xen_add_to_physmap);
374                 break;
375
376         default:
377                 printk(KERN_DEBUG "%s: unknown memory op %d\n", __func__, cmd);
378                 return -ENOSYS;
379         }
380
381         desc = xencomm_map_no_alloc(arg, argsize);
382         if (desc == NULL)
383                 return -EINVAL;
384
385         rc = xencomm_arch_hypercall_memory_op(cmd, desc);
386
387         switch (cmd) {
388         case XENMEM_increase_reservation:
389         case XENMEM_decrease_reservation:
390         case XENMEM_populate_physmap:
391                 set_xen_guest_handle(xmr->extent_start,
392                                      xen_guest_handle(extent_start_va[0]));
393                 break;
394         }
395
396         return rc;
397 }
398 EXPORT_SYMBOL_GPL(xencomm_hypercall_memory_op);
399
400 int
401 xencomm_hypercall_suspend(unsigned long srec)
402 {
403         struct sched_shutdown arg;
404
405         arg.reason = SHUTDOWN_suspend;
406
407         return xencomm_arch_hypercall_sched_op(
408                 SCHEDOP_shutdown, xencomm_map_no_alloc(&arg, sizeof(arg)));
409 }
410
411 long
412 xencomm_hypercall_vcpu_op(int cmd, int cpu, void *arg)
413 {
414         unsigned int argsize;
415         switch (cmd) {
416         case VCPUOP_register_runstate_memory_area: {
417                 struct vcpu_register_runstate_memory_area *area =
418                         (struct vcpu_register_runstate_memory_area *)arg;
419                 argsize = sizeof(*arg);
420                 set_xen_guest_handle(area->addr.h,
421                      (void *)xencomm_map_no_alloc(area->addr.v,
422                                                   sizeof(area->addr.v)));
423                 break;
424         }
425
426         default:
427                 printk(KERN_DEBUG "%s: unknown vcpu op %d\n", __func__, cmd);
428                 return -ENOSYS;
429         }
430
431         return xencomm_arch_hypercall_vcpu_op(cmd, cpu,
432                                         xencomm_map_no_alloc(arg, argsize));
433 }
434
435 long
436 xencomm_hypercall_opt_feature(void *arg)
437 {
438         return xencomm_arch_hypercall_opt_feature(
439                 xencomm_map_no_alloc(arg,
440                                      sizeof(struct xen_ia64_opt_feature)));
441 }