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 <uapi/asm/epapr_hcalls.h> |
---|
54 | |
---|
55 | #ifndef __ASSEMBLY__ |
---|
56 | #include <linux/types.h> |
---|
57 | #include <linux/errno.h> |
---|
58 | #include <asm/byteorder.h> |
---|
59 | |
---|
60 | /* |
---|
61 | * Hypercall register clobber list |
---|
62 | * |
---|
63 | * These macros are used to define the list of clobbered registers during a |
---|
64 | * hypercall. Technically, registers r0 and r3-r12 are always clobbered, |
---|
65 | * but the gcc inline assembly syntax does not allow us to specify registers |
---|
66 | * on the clobber list that are also on the input/output list. Therefore, |
---|
67 | * the lists of clobbered registers depends on the number of register |
---|
68 | * parmeters ("+r" and "=r") passed to the hypercall. |
---|
69 | * |
---|
70 | * Each assembly block should use one of the HCALL_CLOBBERSx macros. As a |
---|
71 | * general rule, 'x' is the number of parameters passed to the assembly |
---|
72 | * block *except* for r11. |
---|
73 | * |
---|
74 | * If you're not sure, just use the smallest value of 'x' that does not |
---|
75 | * generate a compilation error. Because these are static inline functions, |
---|
76 | * the compiler will only check the clobber list for a function if you |
---|
77 | * compile code that calls that function. |
---|
78 | * |
---|
79 | * r3 and r11 are not included in any clobbers list because they are always |
---|
80 | * listed as output registers. |
---|
81 | * |
---|
82 | * XER, CTR, and LR are currently listed as clobbers because it's uncertain |
---|
83 | * whether they will be clobbered. |
---|
84 | * |
---|
85 | * Note that r11 can be used as an output parameter. |
---|
86 | * |
---|
87 | * The "memory" clobber is only necessary for hcalls where the Hypervisor |
---|
88 | * will read or write guest memory. However, we add it to all hcalls because |
---|
89 | * the impact is minimal, and we want to ensure that it's present for the |
---|
90 | * hcalls that need it. |
---|
91 | */ |
---|
92 | |
---|
93 | /* List of common clobbered registers. Do not use this macro. */ |
---|
94 | #define EV_HCALL_CLOBBERS "r0", "r12", "xer", "ctr", "lr", "cc", "memory" |
---|
95 | |
---|
96 | #define EV_HCALL_CLOBBERS8 EV_HCALL_CLOBBERS |
---|
97 | #define EV_HCALL_CLOBBERS7 EV_HCALL_CLOBBERS8, "r10" |
---|
98 | #define EV_HCALL_CLOBBERS6 EV_HCALL_CLOBBERS7, "r9" |
---|
99 | #define EV_HCALL_CLOBBERS5 EV_HCALL_CLOBBERS6, "r8" |
---|
100 | #define EV_HCALL_CLOBBERS4 EV_HCALL_CLOBBERS5, "r7" |
---|
101 | #define EV_HCALL_CLOBBERS3 EV_HCALL_CLOBBERS4, "r6" |
---|
102 | #define EV_HCALL_CLOBBERS2 EV_HCALL_CLOBBERS3, "r5" |
---|
103 | #define EV_HCALL_CLOBBERS1 EV_HCALL_CLOBBERS2, "r4" |
---|
104 | |
---|
105 | extern bool epapr_paravirt_enabled; |
---|
106 | extern u32 epapr_hypercall_start[]; |
---|
107 | |
---|
108 | #ifdef CONFIG_EPAPR_PARAVIRT |
---|
109 | int __init epapr_paravirt_early_init(void); |
---|
110 | #else |
---|
111 | static inline int epapr_paravirt_early_init(void) { return 0; } |
---|
112 | #endif |
---|
113 | |
---|
114 | /* |
---|
115 | * We use "uintptr_t" to define a register because it's guaranteed to be a |
---|
116 | * 32-bit integer on a 32-bit platform, and a 64-bit integer on a 64-bit |
---|
117 | * platform. |
---|
118 | * |
---|
119 | * All registers are either input/output or output only. Registers that are |
---|
120 | * initialized before making the hypercall are input/output. All |
---|
121 | * input/output registers are represented with "+r". Output-only registers |
---|
122 | * are represented with "=r". Do not specify any unused registers. The |
---|
123 | * clobber list will tell the compiler that the hypercall modifies those |
---|
124 | * registers, which is good enough. |
---|
125 | */ |
---|
126 | |
---|
127 | /** |
---|
128 | * ev_int_set_config - configure the specified interrupt |
---|
129 | * @interrupt: the interrupt number |
---|
130 | * @config: configuration for this interrupt |
---|
131 | * @priority: interrupt priority |
---|
132 | * @destination: destination CPU number |
---|
133 | * |
---|
134 | * Returns 0 for success, or an error code. |
---|
135 | */ |
---|
136 | static inline unsigned int ev_int_set_config(unsigned int interrupt, |
---|
137 | uint32_t config, unsigned int priority, uint32_t destination) |
---|
138 | { |
---|
139 | register uintptr_t r11 __asm__("r11"); |
---|
140 | register uintptr_t r3 __asm__("r3"); |
---|
141 | register uintptr_t r4 __asm__("r4"); |
---|
142 | register uintptr_t r5 __asm__("r5"); |
---|
143 | register uintptr_t r6 __asm__("r6"); |
---|
144 | |
---|
145 | r11 = EV_HCALL_TOKEN(EV_INT_SET_CONFIG); |
---|
146 | r3 = interrupt; |
---|
147 | r4 = config; |
---|
148 | r5 = priority; |
---|
149 | r6 = destination; |
---|
150 | |
---|
151 | asm volatile("bl epapr_hypercall_start" |
---|
152 | : "+r" (r11), "+r" (r3), "+r" (r4), "+r" (r5), "+r" (r6) |
---|
153 | : : EV_HCALL_CLOBBERS4 |
---|
154 | ); |
---|
155 | |
---|
156 | return r3; |
---|
157 | } |
---|
158 | |
---|
159 | /** |
---|
160 | * ev_int_get_config - return the config of the specified interrupt |
---|
161 | * @interrupt: the interrupt number |
---|
162 | * @config: returned configuration for this interrupt |
---|
163 | * @priority: returned interrupt priority |
---|
164 | * @destination: returned destination CPU number |
---|
165 | * |
---|
166 | * Returns 0 for success, or an error code. |
---|
167 | */ |
---|
168 | static inline unsigned int ev_int_get_config(unsigned int interrupt, |
---|
169 | uint32_t *config, unsigned int *priority, uint32_t *destination) |
---|
170 | { |
---|
171 | register uintptr_t r11 __asm__("r11"); |
---|
172 | register uintptr_t r3 __asm__("r3"); |
---|
173 | register uintptr_t r4 __asm__("r4"); |
---|
174 | register uintptr_t r5 __asm__("r5"); |
---|
175 | register uintptr_t r6 __asm__("r6"); |
---|
176 | |
---|
177 | r11 = EV_HCALL_TOKEN(EV_INT_GET_CONFIG); |
---|
178 | r3 = interrupt; |
---|
179 | |
---|
180 | asm volatile("bl epapr_hypercall_start" |
---|
181 | : "+r" (r11), "+r" (r3), "=r" (r4), "=r" (r5), "=r" (r6) |
---|
182 | : : EV_HCALL_CLOBBERS4 |
---|
183 | ); |
---|
184 | |
---|
185 | *config = r4; |
---|
186 | *priority = r5; |
---|
187 | *destination = r6; |
---|
188 | |
---|
189 | return r3; |
---|
190 | } |
---|
191 | |
---|
192 | /** |
---|
193 | * ev_int_set_mask - sets the mask for the specified interrupt source |
---|
194 | * @interrupt: the interrupt number |
---|
195 | * @mask: 0=enable interrupts, 1=disable interrupts |
---|
196 | * |
---|
197 | * Returns 0 for success, or an error code. |
---|
198 | */ |
---|
199 | static inline unsigned int ev_int_set_mask(unsigned int interrupt, |
---|
200 | unsigned int mask) |
---|
201 | { |
---|
202 | register uintptr_t r11 __asm__("r11"); |
---|
203 | register uintptr_t r3 __asm__("r3"); |
---|
204 | register uintptr_t r4 __asm__("r4"); |
---|
205 | |
---|
206 | r11 = EV_HCALL_TOKEN(EV_INT_SET_MASK); |
---|
207 | r3 = interrupt; |
---|
208 | r4 = mask; |
---|
209 | |
---|
210 | asm volatile("bl epapr_hypercall_start" |
---|
211 | : "+r" (r11), "+r" (r3), "+r" (r4) |
---|
212 | : : EV_HCALL_CLOBBERS2 |
---|
213 | ); |
---|
214 | |
---|
215 | return r3; |
---|
216 | } |
---|
217 | |
---|
218 | /** |
---|
219 | * ev_int_get_mask - returns the mask for the specified interrupt source |
---|
220 | * @interrupt: the interrupt number |
---|
221 | * @mask: returned mask for this interrupt (0=enabled, 1=disabled) |
---|
222 | * |
---|
223 | * Returns 0 for success, or an error code. |
---|
224 | */ |
---|
225 | static inline unsigned int ev_int_get_mask(unsigned int interrupt, |
---|
226 | unsigned int *mask) |
---|
227 | { |
---|
228 | register uintptr_t r11 __asm__("r11"); |
---|
229 | register uintptr_t r3 __asm__("r3"); |
---|
230 | register uintptr_t r4 __asm__("r4"); |
---|
231 | |
---|
232 | r11 = EV_HCALL_TOKEN(EV_INT_GET_MASK); |
---|
233 | r3 = interrupt; |
---|
234 | |
---|
235 | asm volatile("bl epapr_hypercall_start" |
---|
236 | : "+r" (r11), "+r" (r3), "=r" (r4) |
---|
237 | : : EV_HCALL_CLOBBERS2 |
---|
238 | ); |
---|
239 | |
---|
240 | *mask = r4; |
---|
241 | |
---|
242 | return r3; |
---|
243 | } |
---|
244 | |
---|
245 | /** |
---|
246 | * ev_int_eoi - signal the end of interrupt processing |
---|
247 | * @interrupt: the interrupt number |
---|
248 | * |
---|
249 | * This function signals the end of processing for the the specified |
---|
250 | * interrupt, which must be the interrupt currently in service. By |
---|
251 | * definition, this is also the highest-priority interrupt. |
---|
252 | * |
---|
253 | * Returns 0 for success, or an error code. |
---|
254 | */ |
---|
255 | static inline unsigned int ev_int_eoi(unsigned int interrupt) |
---|
256 | { |
---|
257 | register uintptr_t r11 __asm__("r11"); |
---|
258 | register uintptr_t r3 __asm__("r3"); |
---|
259 | |
---|
260 | r11 = EV_HCALL_TOKEN(EV_INT_EOI); |
---|
261 | r3 = interrupt; |
---|
262 | |
---|
263 | asm volatile("bl epapr_hypercall_start" |
---|
264 | : "+r" (r11), "+r" (r3) |
---|
265 | : : EV_HCALL_CLOBBERS1 |
---|
266 | ); |
---|
267 | |
---|
268 | return r3; |
---|
269 | } |
---|
270 | |
---|
271 | /** |
---|
272 | * ev_byte_channel_send - send characters to a byte stream |
---|
273 | * @handle: byte stream handle |
---|
274 | * @count: (input) num of chars to send, (output) num chars sent |
---|
275 | * @buffer: pointer to a 16-byte buffer |
---|
276 | * |
---|
277 | * @buffer must be at least 16 bytes long, because all 16 bytes will be |
---|
278 | * read from memory into registers, even if count < 16. |
---|
279 | * |
---|
280 | * Returns 0 for success, or an error code. |
---|
281 | */ |
---|
282 | static inline unsigned int ev_byte_channel_send(unsigned int handle, |
---|
283 | unsigned int *count, const char buffer[EV_BYTE_CHANNEL_MAX_BYTES]) |
---|
284 | { |
---|
285 | register uintptr_t r11 __asm__("r11"); |
---|
286 | register uintptr_t r3 __asm__("r3"); |
---|
287 | register uintptr_t r4 __asm__("r4"); |
---|
288 | register uintptr_t r5 __asm__("r5"); |
---|
289 | register uintptr_t r6 __asm__("r6"); |
---|
290 | register uintptr_t r7 __asm__("r7"); |
---|
291 | register uintptr_t r8 __asm__("r8"); |
---|
292 | const uint32_t *p = (const uint32_t *) buffer; |
---|
293 | |
---|
294 | r11 = EV_HCALL_TOKEN(EV_BYTE_CHANNEL_SEND); |
---|
295 | r3 = handle; |
---|
296 | r4 = *count; |
---|
297 | r5 = be32_to_cpu(p[0]); |
---|
298 | r6 = be32_to_cpu(p[1]); |
---|
299 | r7 = be32_to_cpu(p[2]); |
---|
300 | r8 = be32_to_cpu(p[3]); |
---|
301 | |
---|
302 | asm volatile("bl epapr_hypercall_start" |
---|
303 | : "+r" (r11), "+r" (r3), |
---|
304 | "+r" (r4), "+r" (r5), "+r" (r6), "+r" (r7), "+r" (r8) |
---|
305 | : : EV_HCALL_CLOBBERS6 |
---|
306 | ); |
---|
307 | |
---|
308 | *count = r4; |
---|
309 | |
---|
310 | return r3; |
---|
311 | } |
---|
312 | |
---|
313 | /** |
---|
314 | * ev_byte_channel_receive - fetch characters from a byte channel |
---|
315 | * @handle: byte channel handle |
---|
316 | * @count: (input) max num of chars to receive, (output) num chars received |
---|
317 | * @buffer: pointer to a 16-byte buffer |
---|
318 | * |
---|
319 | * The size of @buffer must be at least 16 bytes, even if you request fewer |
---|
320 | * than 16 characters, because we always write 16 bytes to @buffer. This is |
---|
321 | * for performance reasons. |
---|
322 | * |
---|
323 | * Returns 0 for success, or an error code. |
---|
324 | */ |
---|
325 | static inline unsigned int ev_byte_channel_receive(unsigned int handle, |
---|
326 | unsigned int *count, char buffer[EV_BYTE_CHANNEL_MAX_BYTES]) |
---|
327 | { |
---|
328 | register uintptr_t r11 __asm__("r11"); |
---|
329 | register uintptr_t r3 __asm__("r3"); |
---|
330 | register uintptr_t r4 __asm__("r4"); |
---|
331 | register uintptr_t r5 __asm__("r5"); |
---|
332 | register uintptr_t r6 __asm__("r6"); |
---|
333 | register uintptr_t r7 __asm__("r7"); |
---|
334 | register uintptr_t r8 __asm__("r8"); |
---|
335 | uint32_t *p = (uint32_t *) buffer; |
---|
336 | |
---|
337 | r11 = EV_HCALL_TOKEN(EV_BYTE_CHANNEL_RECEIVE); |
---|
338 | r3 = handle; |
---|
339 | r4 = *count; |
---|
340 | |
---|
341 | asm volatile("bl epapr_hypercall_start" |
---|
342 | : "+r" (r11), "+r" (r3), "+r" (r4), |
---|
343 | "=r" (r5), "=r" (r6), "=r" (r7), "=r" (r8) |
---|
344 | : : EV_HCALL_CLOBBERS6 |
---|
345 | ); |
---|
346 | |
---|
347 | *count = r4; |
---|
348 | p[0] = cpu_to_be32(r5); |
---|
349 | p[1] = cpu_to_be32(r6); |
---|
350 | p[2] = cpu_to_be32(r7); |
---|
351 | p[3] = cpu_to_be32(r8); |
---|
352 | |
---|
353 | return r3; |
---|
354 | } |
---|
355 | |
---|
356 | /** |
---|
357 | * ev_byte_channel_poll - returns the status of the byte channel buffers |
---|
358 | * @handle: byte channel handle |
---|
359 | * @rx_count: returned count of bytes in receive queue |
---|
360 | * @tx_count: returned count of free space in transmit queue |
---|
361 | * |
---|
362 | * This function reports the amount of data in the receive queue (i.e. the |
---|
363 | * number of bytes you can read), and the amount of free space in the transmit |
---|
364 | * queue (i.e. the number of bytes you can write). |
---|
365 | * |
---|
366 | * Returns 0 for success, or an error code. |
---|
367 | */ |
---|
368 | static inline unsigned int ev_byte_channel_poll(unsigned int handle, |
---|
369 | unsigned int *rx_count, unsigned int *tx_count) |
---|
370 | { |
---|
371 | register uintptr_t r11 __asm__("r11"); |
---|
372 | register uintptr_t r3 __asm__("r3"); |
---|
373 | register uintptr_t r4 __asm__("r4"); |
---|
374 | register uintptr_t r5 __asm__("r5"); |
---|
375 | |
---|
376 | r11 = EV_HCALL_TOKEN(EV_BYTE_CHANNEL_POLL); |
---|
377 | r3 = handle; |
---|
378 | |
---|
379 | asm volatile("bl epapr_hypercall_start" |
---|
380 | : "+r" (r11), "+r" (r3), "=r" (r4), "=r" (r5) |
---|
381 | : : EV_HCALL_CLOBBERS3 |
---|
382 | ); |
---|
383 | |
---|
384 | *rx_count = r4; |
---|
385 | *tx_count = r5; |
---|
386 | |
---|
387 | return r3; |
---|
388 | } |
---|
389 | |
---|
390 | /** |
---|
391 | * ev_int_iack - acknowledge an interrupt |
---|
392 | * @handle: handle to the target interrupt controller |
---|
393 | * @vector: returned interrupt vector |
---|
394 | * |
---|
395 | * If handle is zero, the function returns the next interrupt source |
---|
396 | * number to be handled irrespective of the hierarchy or cascading |
---|
397 | * of interrupt controllers. If non-zero, specifies a handle to the |
---|
398 | * interrupt controller that is the target of the acknowledge. |
---|
399 | * |
---|
400 | * Returns 0 for success, or an error code. |
---|
401 | */ |
---|
402 | static inline unsigned int ev_int_iack(unsigned int handle, |
---|
403 | unsigned int *vector) |
---|
404 | { |
---|
405 | register uintptr_t r11 __asm__("r11"); |
---|
406 | register uintptr_t r3 __asm__("r3"); |
---|
407 | register uintptr_t r4 __asm__("r4"); |
---|
408 | |
---|
409 | r11 = EV_HCALL_TOKEN(EV_INT_IACK); |
---|
410 | r3 = handle; |
---|
411 | |
---|
412 | asm volatile("bl epapr_hypercall_start" |
---|
413 | : "+r" (r11), "+r" (r3), "=r" (r4) |
---|
414 | : : EV_HCALL_CLOBBERS2 |
---|
415 | ); |
---|
416 | |
---|
417 | *vector = r4; |
---|
418 | |
---|
419 | return r3; |
---|
420 | } |
---|
421 | |
---|
422 | /** |
---|
423 | * ev_doorbell_send - send a doorbell to another partition |
---|
424 | * @handle: doorbell send handle |
---|
425 | * |
---|
426 | * Returns 0 for success, or an error code. |
---|
427 | */ |
---|
428 | static inline unsigned int ev_doorbell_send(unsigned int handle) |
---|
429 | { |
---|
430 | register uintptr_t r11 __asm__("r11"); |
---|
431 | register uintptr_t r3 __asm__("r3"); |
---|
432 | |
---|
433 | r11 = EV_HCALL_TOKEN(EV_DOORBELL_SEND); |
---|
434 | r3 = handle; |
---|
435 | |
---|
436 | asm volatile("bl epapr_hypercall_start" |
---|
437 | : "+r" (r11), "+r" (r3) |
---|
438 | : : EV_HCALL_CLOBBERS1 |
---|
439 | ); |
---|
440 | |
---|
441 | return r3; |
---|
442 | } |
---|
443 | |
---|
444 | /** |
---|
445 | * ev_idle -- wait for next interrupt on this core |
---|
446 | * |
---|
447 | * Returns 0 for success, or an error code. |
---|
448 | */ |
---|
449 | static inline unsigned int ev_idle(void) |
---|
450 | { |
---|
451 | register uintptr_t r11 __asm__("r11"); |
---|
452 | register uintptr_t r3 __asm__("r3"); |
---|
453 | |
---|
454 | r11 = EV_HCALL_TOKEN(EV_IDLE); |
---|
455 | |
---|
456 | asm volatile("bl epapr_hypercall_start" |
---|
457 | : "+r" (r11), "=r" (r3) |
---|
458 | : : EV_HCALL_CLOBBERS1 |
---|
459 | ); |
---|
460 | |
---|
461 | return r3; |
---|
462 | } |
---|
463 | |
---|
464 | #ifdef CONFIG_EPAPR_PARAVIRT |
---|
465 | static inline unsigned long epapr_hypercall(unsigned long *in, |
---|
466 | unsigned long *out, |
---|
467 | unsigned long nr) |
---|
468 | { |
---|
469 | unsigned long register r0 asm("r0"); |
---|
470 | unsigned long register r3 asm("r3") = in[0]; |
---|
471 | unsigned long register r4 asm("r4") = in[1]; |
---|
472 | unsigned long register r5 asm("r5") = in[2]; |
---|
473 | unsigned long register r6 asm("r6") = in[3]; |
---|
474 | unsigned long register r7 asm("r7") = in[4]; |
---|
475 | unsigned long register r8 asm("r8") = in[5]; |
---|
476 | unsigned long register r9 asm("r9") = in[6]; |
---|
477 | unsigned long register r10 asm("r10") = in[7]; |
---|
478 | unsigned long register r11 asm("r11") = nr; |
---|
479 | unsigned long register r12 asm("r12"); |
---|
480 | |
---|
481 | asm volatile("bl epapr_hypercall_start" |
---|
482 | : "=r"(r0), "=r"(r3), "=r"(r4), "=r"(r5), "=r"(r6), |
---|
483 | "=r"(r7), "=r"(r8), "=r"(r9), "=r"(r10), "=r"(r11), |
---|
484 | "=r"(r12) |
---|
485 | : "r"(r3), "r"(r4), "r"(r5), "r"(r6), "r"(r7), "r"(r8), |
---|
486 | "r"(r9), "r"(r10), "r"(r11) |
---|
487 | : "memory", "cc", "xer", "ctr", "lr"); |
---|
488 | |
---|
489 | out[0] = r4; |
---|
490 | out[1] = r5; |
---|
491 | out[2] = r6; |
---|
492 | out[3] = r7; |
---|
493 | out[4] = r8; |
---|
494 | out[5] = r9; |
---|
495 | out[6] = r10; |
---|
496 | out[7] = r11; |
---|
497 | |
---|
498 | return r3; |
---|
499 | } |
---|
500 | #else |
---|
501 | static unsigned long epapr_hypercall(unsigned long *in, |
---|
502 | unsigned long *out, |
---|
503 | unsigned long nr) |
---|
504 | { |
---|
505 | return EV_UNIMPLEMENTED; |
---|
506 | } |
---|
507 | #endif |
---|
508 | |
---|
509 | static inline long epapr_hypercall0_1(unsigned int nr, unsigned long *r2) |
---|
510 | { |
---|
511 | unsigned long in[8]; |
---|
512 | unsigned long out[8]; |
---|
513 | unsigned long r; |
---|
514 | |
---|
515 | r = epapr_hypercall(in, out, nr); |
---|
516 | *r2 = out[0]; |
---|
517 | |
---|
518 | return r; |
---|
519 | } |
---|
520 | |
---|
521 | static inline long epapr_hypercall0(unsigned int nr) |
---|
522 | { |
---|
523 | unsigned long in[8]; |
---|
524 | unsigned long out[8]; |
---|
525 | |
---|
526 | return epapr_hypercall(in, out, nr); |
---|
527 | } |
---|
528 | |
---|
529 | static inline long epapr_hypercall1(unsigned int nr, unsigned long p1) |
---|
530 | { |
---|
531 | unsigned long in[8]; |
---|
532 | unsigned long out[8]; |
---|
533 | |
---|
534 | in[0] = p1; |
---|
535 | return epapr_hypercall(in, out, nr); |
---|
536 | } |
---|
537 | |
---|
538 | static inline long epapr_hypercall2(unsigned int nr, unsigned long p1, |
---|
539 | unsigned long p2) |
---|
540 | { |
---|
541 | unsigned long in[8]; |
---|
542 | unsigned long out[8]; |
---|
543 | |
---|
544 | in[0] = p1; |
---|
545 | in[1] = p2; |
---|
546 | return epapr_hypercall(in, out, nr); |
---|
547 | } |
---|
548 | |
---|
549 | static inline long epapr_hypercall3(unsigned int nr, unsigned long p1, |
---|
550 | unsigned long p2, unsigned long p3) |
---|
551 | { |
---|
552 | unsigned long in[8]; |
---|
553 | unsigned long out[8]; |
---|
554 | |
---|
555 | in[0] = p1; |
---|
556 | in[1] = p2; |
---|
557 | in[2] = p3; |
---|
558 | return epapr_hypercall(in, out, nr); |
---|
559 | } |
---|
560 | |
---|
561 | static inline long epapr_hypercall4(unsigned int nr, unsigned long p1, |
---|
562 | unsigned long p2, unsigned long p3, |
---|
563 | unsigned long p4) |
---|
564 | { |
---|
565 | unsigned long in[8]; |
---|
566 | unsigned long out[8]; |
---|
567 | |
---|
568 | in[0] = p1; |
---|
569 | in[1] = p2; |
---|
570 | in[2] = p3; |
---|
571 | in[3] = p4; |
---|
572 | return epapr_hypercall(in, out, nr); |
---|
573 | } |
---|
574 | #endif /* !__ASSEMBLY__ */ |
---|
575 | #endif /* _EPAPR_HCALLS_H */ |
---|