aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTimur Tabi <timur@freescale.com>2011-05-19 09:54:27 -0400
committerKumar Gala <galak@kernel.crashing.org>2011-06-27 09:30:19 -0400
commitbd497fc9782769d5bce58fbf468eabfce9e98ce0 (patch)
tree0dcbc696f096c42d9e6604ef6a07e167a5e01225
parent6ec36b5848a8336d3a0010727b9365c3254d2d2e (diff)
powerpc: introduce ePAPR embedded hypervisor hcall interface
ePAPR hypervisors provide operating system services via a "hypercall" interface. The following steps need to be performed to make an hcall: 1. Load r11 with the hcall number 2. Load specific other registers with parameters 3. Issue instrucion "sc 1" 4. The return code is in r3 5. Other returned parameters are in other registers. To provide this service to the kernel, these steps are wrapped in inline assembly functions. Standard ePAPR hcalls are in epapr_hcalls.h, and Freescale extensions are in fsl_hcalls.h. Signed-off-by: Timur Tabi <timur@freescale.com> Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
-rw-r--r--arch/powerpc/include/asm/epapr_hcalls.h502
-rw-r--r--arch/powerpc/include/asm/fsl_hcalls.h655
2 files changed, 1157 insertions, 0 deletions
diff --git a/arch/powerpc/include/asm/epapr_hcalls.h b/arch/powerpc/include/asm/epapr_hcalls.h
new file mode 100644
index 00000000000..f3b0c2cc9fe
--- /dev/null
+++ b/arch/powerpc/include/asm/epapr_hcalls.h
@@ -0,0 +1,502 @@
1/*
2 * ePAPR hcall interface
3 *
4 * Copyright 2008-2011 Freescale Semiconductor, Inc.
5 *
6 * Author: Timur Tabi <timur@freescale.com>
7 *
8 * This file is provided under a dual BSD/GPL license. When using or
9 * redistributing this file, you may do so under either license.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions are met:
13 * * Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * * Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * * Neither the name of Freescale Semiconductor nor the
19 * names of its contributors may be used to endorse or promote products
20 * derived from this software without specific prior written permission.
21 *
22 *
23 * ALTERNATIVELY, this software may be distributed under the terms of the
24 * GNU General Public License ("GPL") as published by the Free Software
25 * Foundation, either version 2 of that License or (at your option) any
26 * later version.
27 *
28 * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
29 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
30 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
31 * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
32 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
33 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
34 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
35 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
37 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 */
39
40/* A "hypercall" is an "sc 1" instruction. This header file file provides C
41 * wrapper functions for the ePAPR hypervisor interface. It is inteded
42 * for use by Linux device drivers and other operating systems.
43 *
44 * The hypercalls are implemented as inline assembly, rather than assembly
45 * language functions in a .S file, for optimization. It allows
46 * the caller to issue the hypercall instruction directly, improving both
47 * performance and memory footprint.
48 */
49
50#ifndef _EPAPR_HCALLS_H
51#define _EPAPR_HCALLS_H
52
53#include <linux/types.h>
54#include <linux/errno.h>
55#include <asm/byteorder.h>
56
57#define EV_BYTE_CHANNEL_SEND 1
58#define EV_BYTE_CHANNEL_RECEIVE 2
59#define EV_BYTE_CHANNEL_POLL 3
60#define EV_INT_SET_CONFIG 4
61#define EV_INT_GET_CONFIG 5
62#define EV_INT_SET_MASK 6
63#define EV_INT_GET_MASK 7
64#define EV_INT_IACK 9
65#define EV_INT_EOI 10
66#define EV_INT_SEND_IPI 11
67#define EV_INT_SET_TASK_PRIORITY 12
68#define EV_INT_GET_TASK_PRIORITY 13
69#define EV_DOORBELL_SEND 14
70#define EV_MSGSND 15
71#define EV_IDLE 16
72
73/* vendor ID: epapr */
74#define EV_LOCAL_VENDOR_ID 0 /* for private use */
75#define EV_EPAPR_VENDOR_ID 1
76#define EV_FSL_VENDOR_ID 2 /* Freescale Semiconductor */
77#define EV_IBM_VENDOR_ID 3 /* IBM */
78#define EV_GHS_VENDOR_ID 4 /* Green Hills Software */
79#define EV_ENEA_VENDOR_ID 5 /* Enea */
80#define EV_WR_VENDOR_ID 6 /* Wind River Systems */
81#define EV_AMCC_VENDOR_ID 7 /* Applied Micro Circuits */
82#define EV_KVM_VENDOR_ID 42 /* KVM */
83
84/* The max number of bytes that a byte channel can send or receive per call */
85#define EV_BYTE_CHANNEL_MAX_BYTES 16
86
87
88#define _EV_HCALL_TOKEN(id, num) (((id) << 16) | (num))
89#define EV_HCALL_TOKEN(hcall_num) _EV_HCALL_TOKEN(EV_EPAPR_VENDOR_ID, hcall_num)
90
91/* epapr error codes */
92#define EV_EPERM 1 /* Operation not permitted */
93#define EV_ENOENT 2 /* Entry Not Found */
94#define EV_EIO 3 /* I/O error occured */
95#define EV_EAGAIN 4 /* The operation had insufficient
96 * resources to complete and should be
97 * retried
98 */
99#define EV_ENOMEM 5 /* There was insufficient memory to
100 * complete the operation */
101#define EV_EFAULT 6 /* Bad guest address */
102#define EV_ENODEV 7 /* No such device */
103#define EV_EINVAL 8 /* An argument supplied to the hcall
104 was out of range or invalid */
105#define EV_INTERNAL 9 /* An internal error occured */
106#define EV_CONFIG 10 /* A configuration error was detected */
107#define EV_INVALID_STATE 11 /* The object is in an invalid state */
108#define EV_UNIMPLEMENTED 12 /* Unimplemented hypercall */
109#define EV_BUFFER_OVERFLOW 13 /* Caller-supplied buffer too small */
110
111/*
112 * Hypercall register clobber list
113 *
114 * These macros are used to define the list of clobbered registers during a
115 * hypercall. Technically, registers r0 and r3-r12 are always clobbered,
116 * but the gcc inline assembly syntax does not allow us to specify registers
117 * on the clobber list that are also on the input/output list. Therefore,
118 * the lists of clobbered registers depends on the number of register
119 * parmeters ("+r" and "=r") passed to the hypercall.
120 *
121 * Each assembly block should use one of the HCALL_CLOBBERSx macros. As a
122 * general rule, 'x' is the number of parameters passed to the assembly
123 * block *except* for r11.
124 *
125 * If you're not sure, just use the smallest value of 'x' that does not
126 * generate a compilation error. Because these are static inline functions,
127 * the compiler will only check the clobber list for a function if you
128 * compile code that calls that function.
129 *
130 * r3 and r11 are not included in any clobbers list because they are always
131 * listed as output registers.
132 *
133 * XER, CTR, and LR are currently listed as clobbers because it's uncertain
134 * whether they will be clobbered.
135 *
136 * Note that r11 can be used as an output parameter.
137*/
138
139/* List of common clobbered registers. Do not use this macro. */
140#define EV_HCALL_CLOBBERS "r0", "r12", "xer", "ctr", "lr", "cc"
141
142#define EV_HCALL_CLOBBERS8 EV_HCALL_CLOBBERS
143#define EV_HCALL_CLOBBERS7 EV_HCALL_CLOBBERS8, "r10"
144#define EV_HCALL_CLOBBERS6 EV_HCALL_CLOBBERS7, "r9"
145#define EV_HCALL_CLOBBERS5 EV_HCALL_CLOBBERS6, "r8"
146#define EV_HCALL_CLOBBERS4 EV_HCALL_CLOBBERS5, "r7"
147#define EV_HCALL_CLOBBERS3 EV_HCALL_CLOBBERS4, "r6"
148#define EV_HCALL_CLOBBERS2 EV_HCALL_CLOBBERS3, "r5"
149#define EV_HCALL_CLOBBERS1 EV_HCALL_CLOBBERS2, "r4"
150
151
152/*
153 * We use "uintptr_t" to define a register because it's guaranteed to be a
154 * 32-bit integer on a 32-bit platform, and a 64-bit integer on a 64-bit
155 * platform.
156 *
157 * All registers are either input/output or output only. Registers that are
158 * initialized before making the hypercall are input/output. All
159 * input/output registers are represented with "+r". Output-only registers
160 * are represented with "=r". Do not specify any unused registers. The
161 * clobber list will tell the compiler that the hypercall modifies those
162 * registers, which is good enough.
163 */
164
165/**
166 * ev_int_set_config - configure the specified interrupt
167 * @interrupt: the interrupt number
168 * @config: configuration for this interrupt
169 * @priority: interrupt priority
170 * @destination: destination CPU number
171 *
172 * Returns 0 for success, or an error code.
173 */
174static inline unsigned int ev_int_set_config(unsigned int interrupt,
175 uint32_t config, unsigned int priority, uint32_t destination)
176{
177 register uintptr_t r11 __asm__("r11");
178 register uintptr_t r3 __asm__("r3");
179 register uintptr_t r4 __asm__("r4");
180 register uintptr_t r5 __asm__("r5");
181 register uintptr_t r6 __asm__("r6");
182
183 r11 = EV_HCALL_TOKEN(EV_INT_SET_CONFIG);
184 r3 = interrupt;
185 r4 = config;
186 r5 = priority;
187 r6 = destination;
188
189 __asm__ __volatile__ ("sc 1"
190 : "+r" (r11), "+r" (r3), "+r" (r4), "+r" (r5), "+r" (r6)
191 : : EV_HCALL_CLOBBERS4
192 );
193
194 return r3;
195}
196
197/**
198 * ev_int_get_config - return the config of the specified interrupt
199 * @interrupt: the interrupt number
200 * @config: returned configuration for this interrupt
201 * @priority: returned interrupt priority
202 * @destination: returned destination CPU number
203 *
204 * Returns 0 for success, or an error code.
205 */
206static inline unsigned int ev_int_get_config(unsigned int interrupt,
207 uint32_t *config, unsigned int *priority, uint32_t *destination)
208{
209 register uintptr_t r11 __asm__("r11");
210 register uintptr_t r3 __asm__("r3");
211 register uintptr_t r4 __asm__("r4");
212 register uintptr_t r5 __asm__("r5");
213 register uintptr_t r6 __asm__("r6");
214
215 r11 = EV_HCALL_TOKEN(EV_INT_GET_CONFIG);
216 r3 = interrupt;
217
218 __asm__ __volatile__ ("sc 1"
219 : "+r" (r11), "+r" (r3), "=r" (r4), "=r" (r5), "=r" (r6)
220 : : EV_HCALL_CLOBBERS4
221 );
222
223 *config = r4;
224 *priority = r5;
225 *destination = r6;
226
227 return r3;
228}
229
230/**
231 * ev_int_set_mask - sets the mask for the specified interrupt source
232 * @interrupt: the interrupt number
233 * @mask: 0=enable interrupts, 1=disable interrupts
234 *
235 * Returns 0 for success, or an error code.
236 */
237static inline unsigned int ev_int_set_mask(unsigned int interrupt,
238 unsigned int mask)
239{
240 register uintptr_t r11 __asm__("r11");
241 register uintptr_t r3 __asm__("r3");
242 register uintptr_t r4 __asm__("r4");
243
244 r11 = EV_HCALL_TOKEN(EV_INT_SET_MASK);
245 r3 = interrupt;
246 r4 = mask;
247
248 __asm__ __volatile__ ("sc 1"
249 : "+r" (r11), "+r" (r3), "+r" (r4)
250 : : EV_HCALL_CLOBBERS2
251 );
252
253 return r3;
254}
255
256/**
257 * ev_int_get_mask - returns the mask for the specified interrupt source
258 * @interrupt: the interrupt number
259 * @mask: returned mask for this interrupt (0=enabled, 1=disabled)
260 *
261 * Returns 0 for success, or an error code.
262 */
263static inline unsigned int ev_int_get_mask(unsigned int interrupt,
264 unsigned int *mask)
265{
266 register uintptr_t r11 __asm__("r11");
267 register uintptr_t r3 __asm__("r3");
268 register uintptr_t r4 __asm__("r4");
269
270 r11 = EV_HCALL_TOKEN(EV_INT_GET_MASK);
271 r3 = interrupt;
272
273 __asm__ __volatile__ ("sc 1"
274 : "+r" (r11), "+r" (r3), "=r" (r4)
275 : : EV_HCALL_CLOBBERS2
276 );
277
278 *mask = r4;
279
280 return r3;
281}
282
283/**
284 * ev_int_eoi - signal the end of interrupt processing
285 * @interrupt: the interrupt number
286 *
287 * This function signals the end of processing for the the specified
288 * interrupt, which must be the interrupt currently in service. By
289 * definition, this is also the highest-priority interrupt.
290 *
291 * Returns 0 for success, or an error code.
292 */
293static inline unsigned int ev_int_eoi(unsigned int interrupt)
294{
295 register uintptr_t r11 __asm__("r11");
296 register uintptr_t r3 __asm__("r3");
297
298 r11 = EV_HCALL_TOKEN(EV_INT_EOI);
299 r3 = interrupt;
300
301 __asm__ __volatile__ ("sc 1"
302 : "+r" (r11), "+r" (r3)
303 : : EV_HCALL_CLOBBERS1
304 );
305
306 return r3;
307}
308
309/**
310 * ev_byte_channel_send - send characters to a byte stream
311 * @handle: byte stream handle
312 * @count: (input) num of chars to send, (output) num chars sent
313 * @buffer: pointer to a 16-byte buffer
314 *
315 * @buffer must be at least 16 bytes long, because all 16 bytes will be
316 * read from memory into registers, even if count < 16.
317 *
318 * Returns 0 for success, or an error code.
319 */
320static inline unsigned int ev_byte_channel_send(unsigned int handle,
321 unsigned int *count, const char buffer[EV_BYTE_CHANNEL_MAX_BYTES])
322{
323 register uintptr_t r11 __asm__("r11");
324 register uintptr_t r3 __asm__("r3");
325 register uintptr_t r4 __asm__("r4");
326 register uintptr_t r5 __asm__("r5");
327 register uintptr_t r6 __asm__("r6");
328 register uintptr_t r7 __asm__("r7");
329 register uintptr_t r8 __asm__("r8");
330 const uint32_t *p = (const uint32_t *) buffer;
331
332 r11 = EV_HCALL_TOKEN(EV_BYTE_CHANNEL_SEND);
333 r3 = handle;
334 r4 = *count;
335 r5 = be32_to_cpu(p[0]);
336 r6 = be32_to_cpu(p[1]);
337 r7 = be32_to_cpu(p[2]);
338 r8 = be32_to_cpu(p[3]);
339
340 __asm__ __volatile__ ("sc 1"
341 : "+r" (r11), "+r" (r3),
342 "+r" (r4), "+r" (r5), "+r" (r6), "+r" (r7), "+r" (r8)
343 : : EV_HCALL_CLOBBERS6
344 );
345
346 *count = r4;
347
348 return r3;
349}
350
351/**
352 * ev_byte_channel_receive - fetch characters from a byte channel
353 * @handle: byte channel handle
354 * @count: (input) max num of chars to receive, (output) num chars received
355 * @buffer: pointer to a 16-byte buffer
356 *
357 * The size of @buffer must be at least 16 bytes, even if you request fewer
358 * than 16 characters, because we always write 16 bytes to @buffer. This is
359 * for performance reasons.
360 *
361 * Returns 0 for success, or an error code.
362 */
363static inline unsigned int ev_byte_channel_receive(unsigned int handle,
364 unsigned int *count, char buffer[EV_BYTE_CHANNEL_MAX_BYTES])
365{
366 register uintptr_t r11 __asm__("r11");
367 register uintptr_t r3 __asm__("r3");
368 register uintptr_t r4 __asm__("r4");
369 register uintptr_t r5 __asm__("r5");
370 register uintptr_t r6 __asm__("r6");
371 register uintptr_t r7 __asm__("r7");
372 register uintptr_t r8 __asm__("r8");
373 uint32_t *p = (uint32_t *) buffer;
374
375 r11 = EV_HCALL_TOKEN(EV_BYTE_CHANNEL_RECEIVE);
376 r3 = handle;
377 r4 = *count;
378
379 __asm__ __volatile__ ("sc 1"
380 : "+r" (r11), "+r" (r3), "+r" (r4),
381 "=r" (r5), "=r" (r6), "=r" (r7), "=r" (r8)
382 : : EV_HCALL_CLOBBERS6
383 );
384
385 *count = r4;
386 p[0] = cpu_to_be32(r5);
387 p[1] = cpu_to_be32(r6);
388 p[2] = cpu_to_be32(r7);
389 p[3] = cpu_to_be32(r8);
390
391 return r3;
392}
393
394/**
395 * ev_byte_channel_poll - returns the status of the byte channel buffers
396 * @handle: byte channel handle
397 * @rx_count: returned count of bytes in receive queue
398 * @tx_count: returned count of free space in transmit queue
399 *
400 * This function reports the amount of data in the receive queue (i.e. the
401 * number of bytes you can read), and the amount of free space in the transmit
402 * queue (i.e. the number of bytes you can write).
403 *
404 * Returns 0 for success, or an error code.
405 */
406static inline unsigned int ev_byte_channel_poll(unsigned int handle,
407 unsigned int *rx_count, unsigned int *tx_count)
408{
409 register uintptr_t r11 __asm__("r11");
410 register uintptr_t r3 __asm__("r3");
411 register uintptr_t r4 __asm__("r4");
412 register uintptr_t r5 __asm__("r5");
413
414 r11 = EV_HCALL_TOKEN(EV_BYTE_CHANNEL_POLL);
415 r3 = handle;
416
417 __asm__ __volatile__ ("sc 1"
418 : "+r" (r11), "+r" (r3), "=r" (r4), "=r" (r5)
419 : : EV_HCALL_CLOBBERS3
420 );
421
422 *rx_count = r4;
423 *tx_count = r5;
424
425 return r3;
426}
427
428/**
429 * ev_int_iack - acknowledge an interrupt
430 * @handle: handle to the target interrupt controller
431 * @vector: returned interrupt vector
432 *
433 * If handle is zero, the function returns the next interrupt source
434 * number to be handled irrespective of the hierarchy or cascading
435 * of interrupt controllers. If non-zero, specifies a handle to the
436 * interrupt controller that is the target of the acknowledge.
437 *
438 * Returns 0 for success, or an error code.
439 */
440static inline unsigned int ev_int_iack(unsigned int handle,
441 unsigned int *vector)
442{
443 register uintptr_t r11 __asm__("r11");
444 register uintptr_t r3 __asm__("r3");
445 register uintptr_t r4 __asm__("r4");
446
447 r11 = EV_HCALL_TOKEN(EV_INT_IACK);
448 r3 = handle;
449
450 __asm__ __volatile__ ("sc 1"
451 : "+r" (r11), "+r" (r3), "=r" (r4)
452 : : EV_HCALL_CLOBBERS2
453 );
454
455 *vector = r4;
456
457 return r3;
458}
459
460/**
461 * ev_doorbell_send - send a doorbell to another partition
462 * @handle: doorbell send handle
463 *
464 * Returns 0 for success, or an error code.
465 */
466static inline unsigned int ev_doorbell_send(unsigned int handle)
467{
468 register uintptr_t r11 __asm__("r11");
469 register uintptr_t r3 __asm__("r3");
470
471 r11 = EV_HCALL_TOKEN(EV_DOORBELL_SEND);
472 r3 = handle;
473
474 __asm__ __volatile__ ("sc 1"
475 : "+r" (r11), "+r" (r3)
476 : : EV_HCALL_CLOBBERS1
477 );
478
479 return r3;
480}
481
482/**
483 * ev_idle -- wait for next interrupt on this core
484 *
485 * Returns 0 for success, or an error code.
486 */
487static inline unsigned int ev_idle(void)
488{
489 register uintptr_t r11 __asm__("r11");
490 register uintptr_t r3 __asm__("r3");
491
492 r11 = EV_HCALL_TOKEN(EV_IDLE);
493
494 __asm__ __volatile__ ("sc 1"
495 : "+r" (r11), "=r" (r3)
496 : : EV_HCALL_CLOBBERS1
497 );
498
499 return r3;
500}
501
502#endif
diff --git a/arch/powerpc/include/asm/fsl_hcalls.h b/arch/powerpc/include/asm/fsl_hcalls.h
new file mode 100644
index 00000000000..922d9b5fe3d
--- /dev/null
+++ b/arch/powerpc/include/asm/fsl_hcalls.h
@@ -0,0 +1,655 @@
1/*
2 * Freescale hypervisor call interface
3 *
4 * Copyright 2008-2010 Freescale Semiconductor, Inc.
5 *
6 * Author: Timur Tabi <timur@freescale.com>
7 *
8 * This file is provided under a dual BSD/GPL license. When using or
9 * redistributing this file, you may do so under either license.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions are met:
13 * * Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * * Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * * Neither the name of Freescale Semiconductor nor the
19 * names of its contributors may be used to endorse or promote products
20 * derived from this software without specific prior written permission.
21 *
22 *
23 * ALTERNATIVELY, this software may be distributed under the terms of the
24 * GNU General Public License ("GPL") as published by the Free Software
25 * Foundation, either version 2 of that License or (at your option) any
26 * later version.
27 *
28 * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
29 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
30 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
31 * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
32 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
33 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
34 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
35 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
37 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 */
39
40#ifndef _FSL_HCALLS_H
41#define _FSL_HCALLS_H
42
43#include <linux/types.h>
44#include <linux/errno.h>
45#include <asm/byteorder.h>
46#include <asm/epapr_hcalls.h>
47
48#define FH_API_VERSION 1
49
50#define FH_ERR_GET_INFO 1
51#define FH_PARTITION_GET_DTPROP 2
52#define FH_PARTITION_SET_DTPROP 3
53#define FH_PARTITION_RESTART 4
54#define FH_PARTITION_GET_STATUS 5
55#define FH_PARTITION_START 6
56#define FH_PARTITION_STOP 7
57#define FH_PARTITION_MEMCPY 8
58#define FH_DMA_ENABLE 9
59#define FH_DMA_DISABLE 10
60#define FH_SEND_NMI 11
61#define FH_VMPIC_GET_MSIR 12
62#define FH_SYSTEM_RESET 13
63#define FH_GET_CORE_STATE 14
64#define FH_ENTER_NAP 15
65#define FH_EXIT_NAP 16
66#define FH_CLAIM_DEVICE 17
67#define FH_PARTITION_STOP_DMA 18
68
69/* vendor ID: Freescale Semiconductor */
70#define FH_HCALL_TOKEN(num) _EV_HCALL_TOKEN(EV_FSL_VENDOR_ID, num)
71
72/*
73 * We use "uintptr_t" to define a register because it's guaranteed to be a
74 * 32-bit integer on a 32-bit platform, and a 64-bit integer on a 64-bit
75 * platform.
76 *
77 * All registers are either input/output or output only. Registers that are
78 * initialized before making the hypercall are input/output. All
79 * input/output registers are represented with "+r". Output-only registers
80 * are represented with "=r". Do not specify any unused registers. The
81 * clobber list will tell the compiler that the hypercall modifies those
82 * registers, which is good enough.
83 */
84
85/**
86 * fh_send_nmi - send NMI to virtual cpu(s).
87 * @vcpu_mask: send NMI to virtual cpu(s) specified by this mask.
88 *
89 * Returns 0 for success, or EINVAL for invalid vcpu_mask.
90 */
91static inline unsigned int fh_send_nmi(unsigned int vcpu_mask)
92{
93 register uintptr_t r11 __asm__("r11");
94 register uintptr_t r3 __asm__("r3");
95
96 r11 = FH_HCALL_TOKEN(FH_SEND_NMI);
97 r3 = vcpu_mask;
98
99 __asm__ __volatile__ ("sc 1"
100 : "+r" (r11), "+r" (r3)
101 : : EV_HCALL_CLOBBERS1
102 );
103
104 return r3;
105}
106
107/* Arbitrary limits to avoid excessive memory allocation in hypervisor */
108#define FH_DTPROP_MAX_PATHLEN 4096
109#define FH_DTPROP_MAX_PROPLEN 32768
110
111/**
112 * fh_partiton_get_dtprop - get a property from a guest device tree.
113 * @handle: handle of partition whose device tree is to be accessed
114 * @dtpath_addr: physical address of device tree path to access
115 * @propname_addr: physical address of name of property
116 * @propvalue_addr: physical address of property value buffer
117 * @propvalue_len: length of buffer on entry, length of property on return
118 *
119 * Returns zero on success, non-zero on error.
120 */
121static inline unsigned int fh_partition_get_dtprop(int handle,
122 uint64_t dtpath_addr,
123 uint64_t propname_addr,
124 uint64_t propvalue_addr,
125 uint32_t *propvalue_len)
126{
127 register uintptr_t r11 __asm__("r11");
128 register uintptr_t r3 __asm__("r3");
129 register uintptr_t r4 __asm__("r4");
130 register uintptr_t r5 __asm__("r5");
131 register uintptr_t r6 __asm__("r6");
132 register uintptr_t r7 __asm__("r7");
133 register uintptr_t r8 __asm__("r8");
134 register uintptr_t r9 __asm__("r9");
135 register uintptr_t r10 __asm__("r10");
136
137 r11 = FH_HCALL_TOKEN(FH_PARTITION_GET_DTPROP);
138 r3 = handle;
139
140#ifdef CONFIG_PHYS_64BIT
141 r4 = dtpath_addr >> 32;
142 r6 = propname_addr >> 32;
143 r8 = propvalue_addr >> 32;
144#else
145 r4 = 0;
146 r6 = 0;
147 r8 = 0;
148#endif
149 r5 = (uint32_t)dtpath_addr;
150 r7 = (uint32_t)propname_addr;
151 r9 = (uint32_t)propvalue_addr;
152 r10 = *propvalue_len;
153
154 __asm__ __volatile__ ("sc 1"
155 : "+r" (r11),
156 "+r" (r3), "+r" (r4), "+r" (r5), "+r" (r6), "+r" (r7),
157 "+r" (r8), "+r" (r9), "+r" (r10)
158 : : EV_HCALL_CLOBBERS8
159 );
160
161 *propvalue_len = r4;
162 return r3;
163}
164
165/**
166 * Set a property in a guest device tree.
167 * @handle: handle of partition whose device tree is to be accessed
168 * @dtpath_addr: physical address of device tree path to access
169 * @propname_addr: physical address of name of property
170 * @propvalue_addr: physical address of property value
171 * @propvalue_len: length of property
172 *
173 * Returns zero on success, non-zero on error.
174 */
175static inline unsigned int fh_partition_set_dtprop(int handle,
176 uint64_t dtpath_addr,
177 uint64_t propname_addr,
178 uint64_t propvalue_addr,
179 uint32_t propvalue_len)
180{
181 register uintptr_t r11 __asm__("r11");
182 register uintptr_t r3 __asm__("r3");
183 register uintptr_t r4 __asm__("r4");
184 register uintptr_t r6 __asm__("r6");
185 register uintptr_t r8 __asm__("r8");
186 register uintptr_t r5 __asm__("r5");
187 register uintptr_t r7 __asm__("r7");
188 register uintptr_t r9 __asm__("r9");
189 register uintptr_t r10 __asm__("r10");
190
191 r11 = FH_HCALL_TOKEN(FH_PARTITION_SET_DTPROP);
192 r3 = handle;
193
194#ifdef CONFIG_PHYS_64BIT
195 r4 = dtpath_addr >> 32;
196 r6 = propname_addr >> 32;
197 r8 = propvalue_addr >> 32;
198#else
199 r4 = 0;
200 r6 = 0;
201 r8 = 0;
202#endif
203 r5 = (uint32_t)dtpath_addr;
204 r7 = (uint32_t)propname_addr;
205 r9 = (uint32_t)propvalue_addr;
206 r10 = propvalue_len;
207
208 __asm__ __volatile__ ("sc 1"
209 : "+r" (r11),
210 "+r" (r3), "+r" (r4), "+r" (r5), "+r" (r6), "+r" (r7),
211 "+r" (r8), "+r" (r9), "+r" (r10)
212 : : EV_HCALL_CLOBBERS8
213 );
214
215 return r3;
216}
217
218/**
219 * fh_partition_restart - reboot the current partition
220 * @partition: partition ID
221 *
222 * Returns an error code if reboot failed. Does not return if it succeeds.
223 */
224static inline unsigned int fh_partition_restart(unsigned int partition)
225{
226 register uintptr_t r11 __asm__("r11");
227 register uintptr_t r3 __asm__("r3");
228
229 r11 = FH_HCALL_TOKEN(FH_PARTITION_RESTART);
230 r3 = partition;
231
232 __asm__ __volatile__ ("sc 1"
233 : "+r" (r11), "+r" (r3)
234 : : EV_HCALL_CLOBBERS1
235 );
236
237 return r3;
238}
239
240#define FH_PARTITION_STOPPED 0
241#define FH_PARTITION_RUNNING 1
242#define FH_PARTITION_STARTING 2
243#define FH_PARTITION_STOPPING 3
244#define FH_PARTITION_PAUSING 4
245#define FH_PARTITION_PAUSED 5
246#define FH_PARTITION_RESUMING 6
247
248/**
249 * fh_partition_get_status - gets the status of a partition
250 * @partition: partition ID
251 * @status: returned status code
252 *
253 * Returns 0 for success, or an error code.
254 */
255static inline unsigned int fh_partition_get_status(unsigned int partition,
256 unsigned int *status)
257{
258 register uintptr_t r11 __asm__("r11");
259 register uintptr_t r3 __asm__("r3");
260 register uintptr_t r4 __asm__("r4");
261
262 r11 = FH_HCALL_TOKEN(FH_PARTITION_GET_STATUS);
263 r3 = partition;
264
265 __asm__ __volatile__ ("sc 1"
266 : "+r" (r11), "+r" (r3), "=r" (r4)
267 : : EV_HCALL_CLOBBERS2
268 );
269
270 *status = r4;
271
272 return r3;
273}
274
275/**
276 * fh_partition_start - boots and starts execution of the specified partition
277 * @partition: partition ID
278 * @entry_point: guest physical address to start execution
279 *
280 * The hypervisor creates a 1-to-1 virtual/physical IMA mapping, so at boot
281 * time, guest physical address are the same as guest virtual addresses.
282 *
283 * Returns 0 for success, or an error code.
284 */
285static inline unsigned int fh_partition_start(unsigned int partition,
286 uint32_t entry_point, int load)
287{
288 register uintptr_t r11 __asm__("r11");
289 register uintptr_t r3 __asm__("r3");
290 register uintptr_t r4 __asm__("r4");
291 register uintptr_t r5 __asm__("r5");
292
293 r11 = FH_HCALL_TOKEN(FH_PARTITION_START);
294 r3 = partition;
295 r4 = entry_point;
296 r5 = load;
297
298 __asm__ __volatile__ ("sc 1"
299 : "+r" (r11), "+r" (r3), "+r" (r4), "+r" (r5)
300 : : EV_HCALL_CLOBBERS3
301 );
302
303 return r3;
304}
305
306/**
307 * fh_partition_stop - stops another partition
308 * @partition: partition ID
309 *
310 * Returns 0 for success, or an error code.
311 */
312static inline unsigned int fh_partition_stop(unsigned int partition)
313{
314 register uintptr_t r11 __asm__("r11");
315 register uintptr_t r3 __asm__("r3");
316
317 r11 = FH_HCALL_TOKEN(FH_PARTITION_STOP);
318 r3 = partition;
319
320 __asm__ __volatile__ ("sc 1"
321 : "+r" (r11), "+r" (r3)
322 : : EV_HCALL_CLOBBERS1
323 );
324
325 return r3;
326}
327
328/**
329 * struct fh_sg_list: definition of the fh_partition_memcpy S/G list
330 * @source: guest physical address to copy from
331 * @target: guest physical address to copy to
332 * @size: number of bytes to copy
333 * @reserved: reserved, must be zero
334 *
335 * The scatter/gather list for fh_partition_memcpy() is an array of these
336 * structures. The array must be guest physically contiguous.
337 *
338 * This structure must be aligned on 32-byte boundary, so that no single
339 * strucuture can span two pages.
340 */
341struct fh_sg_list {
342 uint64_t source; /**< guest physical address to copy from */
343 uint64_t target; /**< guest physical address to copy to */
344 uint64_t size; /**< number of bytes to copy */
345 uint64_t reserved; /**< reserved, must be zero */
346} __attribute__ ((aligned(32)));
347
348/**
349 * fh_partition_memcpy - copies data from one guest to another
350 * @source: the ID of the partition to copy from
351 * @target: the ID of the partition to copy to
352 * @sg_list: guest physical address of an array of &fh_sg_list structures
353 * @count: the number of entries in @sg_list
354 *
355 * Returns 0 for success, or an error code.
356 */
357static inline unsigned int fh_partition_memcpy(unsigned int source,
358 unsigned int target, phys_addr_t sg_list, unsigned int count)
359{
360 register uintptr_t r11 __asm__("r11");
361 register uintptr_t r3 __asm__("r3");
362 register uintptr_t r4 __asm__("r4");
363 register uintptr_t r5 __asm__("r5");
364 register uintptr_t r6 __asm__("r6");
365 register uintptr_t r7 __asm__("r7");
366
367 r11 = FH_HCALL_TOKEN(FH_PARTITION_MEMCPY);
368 r3 = source;
369 r4 = target;
370 r5 = (uint32_t) sg_list;
371
372#ifdef CONFIG_PHYS_64BIT
373 r6 = sg_list >> 32;
374#else
375 r6 = 0;
376#endif
377 r7 = count;
378
379 __asm__ __volatile__ ("sc 1"
380 : "+r" (r11),
381 "+r" (r3), "+r" (r4), "+r" (r5), "+r" (r6), "+r" (r7)
382 : : EV_HCALL_CLOBBERS5
383 );
384
385 return r3;
386}
387
388/**
389 * fh_dma_enable - enable DMA for the specified device
390 * @liodn: the LIODN of the I/O device for which to enable DMA
391 *
392 * Returns 0 for success, or an error code.
393 */
394static inline unsigned int fh_dma_enable(unsigned int liodn)
395{
396 register uintptr_t r11 __asm__("r11");
397 register uintptr_t r3 __asm__("r3");
398
399 r11 = FH_HCALL_TOKEN(FH_DMA_ENABLE);
400 r3 = liodn;
401
402 __asm__ __volatile__ ("sc 1"
403 : "+r" (r11), "+r" (r3)
404 : : EV_HCALL_CLOBBERS1
405 );
406
407 return r3;
408}
409
410/**
411 * fh_dma_disable - disable DMA for the specified device
412 * @liodn: the LIODN of the I/O device for which to disable DMA
413 *
414 * Returns 0 for success, or an error code.
415 */
416static inline unsigned int fh_dma_disable(unsigned int liodn)
417{
418 register uintptr_t r11 __asm__("r11");
419 register uintptr_t r3 __asm__("r3");
420
421 r11 = FH_HCALL_TOKEN(FH_DMA_DISABLE);
422 r3 = liodn;
423
424 __asm__ __volatile__ ("sc 1"
425 : "+r" (r11), "+r" (r3)
426 : : EV_HCALL_CLOBBERS1
427 );
428
429 return r3;
430}
431
432
433/**
434 * fh_vmpic_get_msir - returns the MPIC-MSI register value
435 * @interrupt: the interrupt number
436 * @msir_val: returned MPIC-MSI register value
437 *
438 * Returns 0 for success, or an error code.
439 */
440static inline unsigned int fh_vmpic_get_msir(unsigned int interrupt,
441 unsigned int *msir_val)
442{
443 register uintptr_t r11 __asm__("r11");
444 register uintptr_t r3 __asm__("r3");
445 register uintptr_t r4 __asm__("r4");
446
447 r11 = FH_HCALL_TOKEN(FH_VMPIC_GET_MSIR);
448 r3 = interrupt;
449
450 __asm__ __volatile__ ("sc 1"
451 : "+r" (r11), "+r" (r3), "=r" (r4)
452 : : EV_HCALL_CLOBBERS2
453 );
454
455 *msir_val = r4;
456
457 return r3;
458}
459
460/**
461 * fh_system_reset - reset the system
462 *
463 * Returns 0 for success, or an error code.
464 */
465static inline unsigned int fh_system_reset(void)
466{
467 register uintptr_t r11 __asm__("r11");
468 register uintptr_t r3 __asm__("r3");
469
470 r11 = FH_HCALL_TOKEN(FH_SYSTEM_RESET);
471
472 __asm__ __volatile__ ("sc 1"
473 : "+r" (r11), "=r" (r3)
474 : : EV_HCALL_CLOBBERS1
475 );
476
477 return r3;
478}
479
480
481/**
482 * fh_err_get_info - get platform error information
483 * @queue id:
484 * 0 for guest error event queue
485 * 1 for global error event queue
486 *
487 * @pointer to store the platform error data:
488 * platform error data is returned in registers r4 - r11
489 *
490 * Returns 0 for success, or an error code.
491 */
492static inline unsigned int fh_err_get_info(int queue, uint32_t *bufsize,
493 uint32_t addr_hi, uint32_t addr_lo, int peek)
494{
495 register uintptr_t r11 __asm__("r11");
496 register uintptr_t r3 __asm__("r3");
497 register uintptr_t r4 __asm__("r4");
498 register uintptr_t r5 __asm__("r5");
499 register uintptr_t r6 __asm__("r6");
500 register uintptr_t r7 __asm__("r7");
501
502 r11 = FH_HCALL_TOKEN(FH_ERR_GET_INFO);
503 r3 = queue;
504 r4 = *bufsize;
505 r5 = addr_hi;
506 r6 = addr_lo;
507 r7 = peek;
508
509 __asm__ __volatile__ ("sc 1"
510 : "+r" (r11), "+r" (r3), "+r" (r4), "+r" (r5), "+r" (r6),
511 "+r" (r7)
512 : : EV_HCALL_CLOBBERS5
513 );
514
515 *bufsize = r4;
516
517 return r3;
518}
519
520
521#define FH_VCPU_RUN 0
522#define FH_VCPU_IDLE 1
523#define FH_VCPU_NAP 2
524
525/**
526 * fh_get_core_state - get the state of a vcpu
527 *
528 * @handle: handle of partition containing the vcpu
529 * @vcpu: vcpu number within the partition
530 * @state:the current state of the vcpu, see FH_VCPU_*
531 *
532 * Returns 0 for success, or an error code.
533 */
534static inline unsigned int fh_get_core_state(unsigned int handle,
535 unsigned int vcpu, unsigned int *state)
536{
537 register uintptr_t r11 __asm__("r11");
538 register uintptr_t r3 __asm__("r3");
539 register uintptr_t r4 __asm__("r4");
540
541 r11 = FH_HCALL_TOKEN(FH_GET_CORE_STATE);
542 r3 = handle;
543 r4 = vcpu;
544
545 __asm__ __volatile__ ("sc 1"
546 : "+r" (r11), "+r" (r3), "+r" (r4)
547 : : EV_HCALL_CLOBBERS2
548 );
549
550 *state = r4;
551 return r3;
552}
553
554/**
555 * fh_enter_nap - enter nap on a vcpu
556 *
557 * Note that though the API supports entering nap on a vcpu other
558 * than the caller, this may not be implmented and may return EINVAL.
559 *
560 * @handle: handle of partition containing the vcpu
561 * @vcpu: vcpu number within the partition
562 *
563 * Returns 0 for success, or an error code.
564 */
565static inline unsigned int fh_enter_nap(unsigned int handle, unsigned int vcpu)
566{
567 register uintptr_t r11 __asm__("r11");
568 register uintptr_t r3 __asm__("r3");
569 register uintptr_t r4 __asm__("r4");
570
571 r11 = FH_HCALL_TOKEN(FH_ENTER_NAP);
572 r3 = handle;
573 r4 = vcpu;
574
575 __asm__ __volatile__ ("sc 1"
576 : "+r" (r11), "+r" (r3), "+r" (r4)
577 : : EV_HCALL_CLOBBERS2
578 );
579
580 return r3;
581}
582
583/**
584 * fh_exit_nap - exit nap on a vcpu
585 * @handle: handle of partition containing the vcpu
586 * @vcpu: vcpu number within the partition
587 *
588 * Returns 0 for success, or an error code.
589 */
590static inline unsigned int fh_exit_nap(unsigned int handle, unsigned int vcpu)
591{
592 register uintptr_t r11 __asm__("r11");
593 register uintptr_t r3 __asm__("r3");
594 register uintptr_t r4 __asm__("r4");
595
596 r11 = FH_HCALL_TOKEN(FH_EXIT_NAP);
597 r3 = handle;
598 r4 = vcpu;
599
600 __asm__ __volatile__ ("sc 1"
601 : "+r" (r11), "+r" (r3), "+r" (r4)
602 : : EV_HCALL_CLOBBERS2
603 );
604
605 return r3;
606}
607/**
608 * fh_claim_device - claim a "claimable" shared device
609 * @handle: fsl,hv-device-handle of node to claim
610 *
611 * Returns 0 for success, or an error code.
612 */
613static inline unsigned int fh_claim_device(unsigned int handle)
614{
615 register uintptr_t r11 __asm__("r11");
616 register uintptr_t r3 __asm__("r3");
617
618 r11 = FH_HCALL_TOKEN(FH_CLAIM_DEVICE);
619 r3 = handle;
620
621 __asm__ __volatile__ ("sc 1"
622 : "+r" (r11), "+r" (r3)
623 : : EV_HCALL_CLOBBERS1
624 );
625
626 return r3;
627}
628
629/**
630 * Run deferred DMA disabling on a partition's private devices
631 *
632 * This applies to devices which a partition owns either privately,
633 * or which are claimable and still actively owned by that partition,
634 * and which do not have the no-dma-disable property.
635 *
636 * @handle: partition (must be stopped) whose DMA is to be disabled
637 *
638 * Returns 0 for success, or an error code.
639 */
640static inline unsigned int fh_partition_stop_dma(unsigned int handle)
641{
642 register uintptr_t r11 __asm__("r11");
643 register uintptr_t r3 __asm__("r3");
644
645 r11 = FH_HCALL_TOKEN(FH_PARTITION_STOP_DMA);
646 r3 = handle;
647
648 __asm__ __volatile__ ("sc 1"
649 : "+r" (r11), "+r" (r3)
650 : : EV_HCALL_CLOBBERS1
651 );
652
653 return r3;
654}
655#endif