162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * ePAPR hcall interface
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright 2008-2011 Freescale Semiconductor, Inc.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Author: Timur Tabi <timur@freescale.com>
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * This file is provided under a dual BSD/GPL license.  When using or
962306a36Sopenharmony_ci * redistributing this file, you may do so under either license.
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or without
1262306a36Sopenharmony_ci * modification, are permitted provided that the following conditions are met:
1362306a36Sopenharmony_ci *     * Redistributions of source code must retain the above copyright
1462306a36Sopenharmony_ci *       notice, this list of conditions and the following disclaimer.
1562306a36Sopenharmony_ci *     * Redistributions in binary form must reproduce the above copyright
1662306a36Sopenharmony_ci *       notice, this list of conditions and the following disclaimer in the
1762306a36Sopenharmony_ci *       documentation and/or other materials provided with the distribution.
1862306a36Sopenharmony_ci *     * Neither the name of Freescale Semiconductor nor the
1962306a36Sopenharmony_ci *       names of its contributors may be used to endorse or promote products
2062306a36Sopenharmony_ci *       derived from this software without specific prior written permission.
2162306a36Sopenharmony_ci *
2262306a36Sopenharmony_ci *
2362306a36Sopenharmony_ci * ALTERNATIVELY, this software may be distributed under the terms of the
2462306a36Sopenharmony_ci * GNU General Public License ("GPL") as published by the Free Software
2562306a36Sopenharmony_ci * Foundation, either version 2 of that License or (at your option) any
2662306a36Sopenharmony_ci * later version.
2762306a36Sopenharmony_ci *
2862306a36Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
2962306a36Sopenharmony_ci * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
3062306a36Sopenharmony_ci * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
3162306a36Sopenharmony_ci * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
3262306a36Sopenharmony_ci * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
3362306a36Sopenharmony_ci * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
3462306a36Sopenharmony_ci * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
3562306a36Sopenharmony_ci * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3662306a36Sopenharmony_ci * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
3762306a36Sopenharmony_ci * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3862306a36Sopenharmony_ci */
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci/* A "hypercall" is an "sc 1" instruction.  This header file provides C
4162306a36Sopenharmony_ci * wrapper functions for the ePAPR hypervisor interface.  It is inteded
4262306a36Sopenharmony_ci * for use by Linux device drivers and other operating systems.
4362306a36Sopenharmony_ci *
4462306a36Sopenharmony_ci * The hypercalls are implemented as inline assembly, rather than assembly
4562306a36Sopenharmony_ci * language functions in a .S file, for optimization.  It allows
4662306a36Sopenharmony_ci * the caller to issue the hypercall instruction directly, improving both
4762306a36Sopenharmony_ci * performance and memory footprint.
4862306a36Sopenharmony_ci */
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci#ifndef _EPAPR_HCALLS_H
5162306a36Sopenharmony_ci#define _EPAPR_HCALLS_H
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci#include <uapi/asm/epapr_hcalls.h>
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci#ifndef __ASSEMBLY__
5662306a36Sopenharmony_ci#include <linux/types.h>
5762306a36Sopenharmony_ci#include <linux/errno.h>
5862306a36Sopenharmony_ci#include <asm/byteorder.h>
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci/*
6162306a36Sopenharmony_ci * Hypercall register clobber list
6262306a36Sopenharmony_ci *
6362306a36Sopenharmony_ci * These macros are used to define the list of clobbered registers during a
6462306a36Sopenharmony_ci * hypercall.  Technically, registers r0 and r3-r12 are always clobbered,
6562306a36Sopenharmony_ci * but the gcc inline assembly syntax does not allow us to specify registers
6662306a36Sopenharmony_ci * on the clobber list that are also on the input/output list.  Therefore,
6762306a36Sopenharmony_ci * the lists of clobbered registers depends on the number of register
6862306a36Sopenharmony_ci * parameters ("+r" and "=r") passed to the hypercall.
6962306a36Sopenharmony_ci *
7062306a36Sopenharmony_ci * Each assembly block should use one of the HCALL_CLOBBERSx macros.  As a
7162306a36Sopenharmony_ci * general rule, 'x' is the number of parameters passed to the assembly
7262306a36Sopenharmony_ci * block *except* for r11.
7362306a36Sopenharmony_ci *
7462306a36Sopenharmony_ci * If you're not sure, just use the smallest value of 'x' that does not
7562306a36Sopenharmony_ci * generate a compilation error.  Because these are static inline functions,
7662306a36Sopenharmony_ci * the compiler will only check the clobber list for a function if you
7762306a36Sopenharmony_ci * compile code that calls that function.
7862306a36Sopenharmony_ci *
7962306a36Sopenharmony_ci * r3 and r11 are not included in any clobbers list because they are always
8062306a36Sopenharmony_ci * listed as output registers.
8162306a36Sopenharmony_ci *
8262306a36Sopenharmony_ci * XER, CTR, and LR are currently listed as clobbers because it's uncertain
8362306a36Sopenharmony_ci * whether they will be clobbered.
8462306a36Sopenharmony_ci *
8562306a36Sopenharmony_ci * Note that r11 can be used as an output parameter.
8662306a36Sopenharmony_ci *
8762306a36Sopenharmony_ci * The "memory" clobber is only necessary for hcalls where the Hypervisor
8862306a36Sopenharmony_ci * will read or write guest memory. However, we add it to all hcalls because
8962306a36Sopenharmony_ci * the impact is minimal, and we want to ensure that it's present for the
9062306a36Sopenharmony_ci * hcalls that need it.
9162306a36Sopenharmony_ci*/
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci/* List of common clobbered registers.  Do not use this macro. */
9462306a36Sopenharmony_ci#define EV_HCALL_CLOBBERS "r0", "r12", "xer", "ctr", "lr", "cc", "memory"
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci#define EV_HCALL_CLOBBERS8 EV_HCALL_CLOBBERS
9762306a36Sopenharmony_ci#define EV_HCALL_CLOBBERS7 EV_HCALL_CLOBBERS8, "r10"
9862306a36Sopenharmony_ci#define EV_HCALL_CLOBBERS6 EV_HCALL_CLOBBERS7, "r9"
9962306a36Sopenharmony_ci#define EV_HCALL_CLOBBERS5 EV_HCALL_CLOBBERS6, "r8"
10062306a36Sopenharmony_ci#define EV_HCALL_CLOBBERS4 EV_HCALL_CLOBBERS5, "r7"
10162306a36Sopenharmony_ci#define EV_HCALL_CLOBBERS3 EV_HCALL_CLOBBERS4, "r6"
10262306a36Sopenharmony_ci#define EV_HCALL_CLOBBERS2 EV_HCALL_CLOBBERS3, "r5"
10362306a36Sopenharmony_ci#define EV_HCALL_CLOBBERS1 EV_HCALL_CLOBBERS2, "r4"
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ciextern bool epapr_paravirt_enabled;
10662306a36Sopenharmony_ciextern u32 epapr_hypercall_start[];
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci#ifdef CONFIG_EPAPR_PARAVIRT
10962306a36Sopenharmony_ciint __init epapr_paravirt_early_init(void);
11062306a36Sopenharmony_ci#else
11162306a36Sopenharmony_cistatic inline int epapr_paravirt_early_init(void) { return 0; }
11262306a36Sopenharmony_ci#endif
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci/*
11562306a36Sopenharmony_ci * We use "uintptr_t" to define a register because it's guaranteed to be a
11662306a36Sopenharmony_ci * 32-bit integer on a 32-bit platform, and a 64-bit integer on a 64-bit
11762306a36Sopenharmony_ci * platform.
11862306a36Sopenharmony_ci *
11962306a36Sopenharmony_ci * All registers are either input/output or output only.  Registers that are
12062306a36Sopenharmony_ci * initialized before making the hypercall are input/output.  All
12162306a36Sopenharmony_ci * input/output registers are represented with "+r".  Output-only registers
12262306a36Sopenharmony_ci * are represented with "=r".  Do not specify any unused registers.  The
12362306a36Sopenharmony_ci * clobber list will tell the compiler that the hypercall modifies those
12462306a36Sopenharmony_ci * registers, which is good enough.
12562306a36Sopenharmony_ci */
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci/**
12862306a36Sopenharmony_ci * ev_int_set_config - configure the specified interrupt
12962306a36Sopenharmony_ci * @interrupt: the interrupt number
13062306a36Sopenharmony_ci * @config: configuration for this interrupt
13162306a36Sopenharmony_ci * @priority: interrupt priority
13262306a36Sopenharmony_ci * @destination: destination CPU number
13362306a36Sopenharmony_ci *
13462306a36Sopenharmony_ci * Returns 0 for success, or an error code.
13562306a36Sopenharmony_ci */
13662306a36Sopenharmony_cistatic inline unsigned int ev_int_set_config(unsigned int interrupt,
13762306a36Sopenharmony_ci	uint32_t config, unsigned int priority, uint32_t destination)
13862306a36Sopenharmony_ci{
13962306a36Sopenharmony_ci	register uintptr_t r11 __asm__("r11");
14062306a36Sopenharmony_ci	register uintptr_t r3 __asm__("r3");
14162306a36Sopenharmony_ci	register uintptr_t r4 __asm__("r4");
14262306a36Sopenharmony_ci	register uintptr_t r5 __asm__("r5");
14362306a36Sopenharmony_ci	register uintptr_t r6 __asm__("r6");
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	r11 = EV_HCALL_TOKEN(EV_INT_SET_CONFIG);
14662306a36Sopenharmony_ci	r3  = interrupt;
14762306a36Sopenharmony_ci	r4  = config;
14862306a36Sopenharmony_ci	r5  = priority;
14962306a36Sopenharmony_ci	r6  = destination;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	asm volatile("bl	epapr_hypercall_start"
15262306a36Sopenharmony_ci		: "+r" (r11), "+r" (r3), "+r" (r4), "+r" (r5), "+r" (r6)
15362306a36Sopenharmony_ci		: : EV_HCALL_CLOBBERS4
15462306a36Sopenharmony_ci	);
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	return r3;
15762306a36Sopenharmony_ci}
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci/**
16062306a36Sopenharmony_ci * ev_int_get_config - return the config of the specified interrupt
16162306a36Sopenharmony_ci * @interrupt: the interrupt number
16262306a36Sopenharmony_ci * @config: returned configuration for this interrupt
16362306a36Sopenharmony_ci * @priority: returned interrupt priority
16462306a36Sopenharmony_ci * @destination: returned destination CPU number
16562306a36Sopenharmony_ci *
16662306a36Sopenharmony_ci * Returns 0 for success, or an error code.
16762306a36Sopenharmony_ci */
16862306a36Sopenharmony_cistatic inline unsigned int ev_int_get_config(unsigned int interrupt,
16962306a36Sopenharmony_ci	uint32_t *config, unsigned int *priority, uint32_t *destination)
17062306a36Sopenharmony_ci{
17162306a36Sopenharmony_ci	register uintptr_t r11 __asm__("r11");
17262306a36Sopenharmony_ci	register uintptr_t r3 __asm__("r3");
17362306a36Sopenharmony_ci	register uintptr_t r4 __asm__("r4");
17462306a36Sopenharmony_ci	register uintptr_t r5 __asm__("r5");
17562306a36Sopenharmony_ci	register uintptr_t r6 __asm__("r6");
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	r11 = EV_HCALL_TOKEN(EV_INT_GET_CONFIG);
17862306a36Sopenharmony_ci	r3 = interrupt;
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	asm volatile("bl	epapr_hypercall_start"
18162306a36Sopenharmony_ci		: "+r" (r11), "+r" (r3), "=r" (r4), "=r" (r5), "=r" (r6)
18262306a36Sopenharmony_ci		: : EV_HCALL_CLOBBERS4
18362306a36Sopenharmony_ci	);
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	*config = r4;
18662306a36Sopenharmony_ci	*priority = r5;
18762306a36Sopenharmony_ci	*destination = r6;
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	return r3;
19062306a36Sopenharmony_ci}
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci/**
19362306a36Sopenharmony_ci * ev_int_set_mask - sets the mask for the specified interrupt source
19462306a36Sopenharmony_ci * @interrupt: the interrupt number
19562306a36Sopenharmony_ci * @mask: 0=enable interrupts, 1=disable interrupts
19662306a36Sopenharmony_ci *
19762306a36Sopenharmony_ci * Returns 0 for success, or an error code.
19862306a36Sopenharmony_ci */
19962306a36Sopenharmony_cistatic inline unsigned int ev_int_set_mask(unsigned int interrupt,
20062306a36Sopenharmony_ci	unsigned int mask)
20162306a36Sopenharmony_ci{
20262306a36Sopenharmony_ci	register uintptr_t r11 __asm__("r11");
20362306a36Sopenharmony_ci	register uintptr_t r3 __asm__("r3");
20462306a36Sopenharmony_ci	register uintptr_t r4 __asm__("r4");
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	r11 = EV_HCALL_TOKEN(EV_INT_SET_MASK);
20762306a36Sopenharmony_ci	r3 = interrupt;
20862306a36Sopenharmony_ci	r4 = mask;
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	asm volatile("bl	epapr_hypercall_start"
21162306a36Sopenharmony_ci		: "+r" (r11), "+r" (r3), "+r" (r4)
21262306a36Sopenharmony_ci		: : EV_HCALL_CLOBBERS2
21362306a36Sopenharmony_ci	);
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	return r3;
21662306a36Sopenharmony_ci}
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci/**
21962306a36Sopenharmony_ci * ev_int_get_mask - returns the mask for the specified interrupt source
22062306a36Sopenharmony_ci * @interrupt: the interrupt number
22162306a36Sopenharmony_ci * @mask: returned mask for this interrupt (0=enabled, 1=disabled)
22262306a36Sopenharmony_ci *
22362306a36Sopenharmony_ci * Returns 0 for success, or an error code.
22462306a36Sopenharmony_ci */
22562306a36Sopenharmony_cistatic inline unsigned int ev_int_get_mask(unsigned int interrupt,
22662306a36Sopenharmony_ci	unsigned int *mask)
22762306a36Sopenharmony_ci{
22862306a36Sopenharmony_ci	register uintptr_t r11 __asm__("r11");
22962306a36Sopenharmony_ci	register uintptr_t r3 __asm__("r3");
23062306a36Sopenharmony_ci	register uintptr_t r4 __asm__("r4");
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	r11 = EV_HCALL_TOKEN(EV_INT_GET_MASK);
23362306a36Sopenharmony_ci	r3 = interrupt;
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	asm volatile("bl	epapr_hypercall_start"
23662306a36Sopenharmony_ci		: "+r" (r11), "+r" (r3), "=r" (r4)
23762306a36Sopenharmony_ci		: : EV_HCALL_CLOBBERS2
23862306a36Sopenharmony_ci	);
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	*mask = r4;
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	return r3;
24362306a36Sopenharmony_ci}
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci/**
24662306a36Sopenharmony_ci * ev_int_eoi - signal the end of interrupt processing
24762306a36Sopenharmony_ci * @interrupt: the interrupt number
24862306a36Sopenharmony_ci *
24962306a36Sopenharmony_ci * This function signals the end of processing for the specified
25062306a36Sopenharmony_ci * interrupt, which must be the interrupt currently in service. By
25162306a36Sopenharmony_ci * definition, this is also the highest-priority interrupt.
25262306a36Sopenharmony_ci *
25362306a36Sopenharmony_ci * Returns 0 for success, or an error code.
25462306a36Sopenharmony_ci */
25562306a36Sopenharmony_cistatic inline unsigned int ev_int_eoi(unsigned int interrupt)
25662306a36Sopenharmony_ci{
25762306a36Sopenharmony_ci	register uintptr_t r11 __asm__("r11");
25862306a36Sopenharmony_ci	register uintptr_t r3 __asm__("r3");
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	r11 = EV_HCALL_TOKEN(EV_INT_EOI);
26162306a36Sopenharmony_ci	r3 = interrupt;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	asm volatile("bl	epapr_hypercall_start"
26462306a36Sopenharmony_ci		: "+r" (r11), "+r" (r3)
26562306a36Sopenharmony_ci		: : EV_HCALL_CLOBBERS1
26662306a36Sopenharmony_ci	);
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	return r3;
26962306a36Sopenharmony_ci}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci/**
27262306a36Sopenharmony_ci * ev_byte_channel_send - send characters to a byte stream
27362306a36Sopenharmony_ci * @handle: byte stream handle
27462306a36Sopenharmony_ci * @count: (input) num of chars to send, (output) num chars sent
27562306a36Sopenharmony_ci * @buffer: pointer to a 16-byte buffer
27662306a36Sopenharmony_ci *
27762306a36Sopenharmony_ci * @buffer must be at least 16 bytes long, because all 16 bytes will be
27862306a36Sopenharmony_ci * read from memory into registers, even if count < 16.
27962306a36Sopenharmony_ci *
28062306a36Sopenharmony_ci * Returns 0 for success, or an error code.
28162306a36Sopenharmony_ci */
28262306a36Sopenharmony_cistatic inline unsigned int ev_byte_channel_send(unsigned int handle,
28362306a36Sopenharmony_ci	unsigned int *count, const char buffer[EV_BYTE_CHANNEL_MAX_BYTES])
28462306a36Sopenharmony_ci{
28562306a36Sopenharmony_ci	register uintptr_t r11 __asm__("r11");
28662306a36Sopenharmony_ci	register uintptr_t r3 __asm__("r3");
28762306a36Sopenharmony_ci	register uintptr_t r4 __asm__("r4");
28862306a36Sopenharmony_ci	register uintptr_t r5 __asm__("r5");
28962306a36Sopenharmony_ci	register uintptr_t r6 __asm__("r6");
29062306a36Sopenharmony_ci	register uintptr_t r7 __asm__("r7");
29162306a36Sopenharmony_ci	register uintptr_t r8 __asm__("r8");
29262306a36Sopenharmony_ci	const uint32_t *p = (const uint32_t *) buffer;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	r11 = EV_HCALL_TOKEN(EV_BYTE_CHANNEL_SEND);
29562306a36Sopenharmony_ci	r3 = handle;
29662306a36Sopenharmony_ci	r4 = *count;
29762306a36Sopenharmony_ci	r5 = be32_to_cpu(p[0]);
29862306a36Sopenharmony_ci	r6 = be32_to_cpu(p[1]);
29962306a36Sopenharmony_ci	r7 = be32_to_cpu(p[2]);
30062306a36Sopenharmony_ci	r8 = be32_to_cpu(p[3]);
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	asm volatile("bl	epapr_hypercall_start"
30362306a36Sopenharmony_ci		: "+r" (r11), "+r" (r3),
30462306a36Sopenharmony_ci		  "+r" (r4), "+r" (r5), "+r" (r6), "+r" (r7), "+r" (r8)
30562306a36Sopenharmony_ci		: : EV_HCALL_CLOBBERS6
30662306a36Sopenharmony_ci	);
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	*count = r4;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	return r3;
31162306a36Sopenharmony_ci}
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci/**
31462306a36Sopenharmony_ci * ev_byte_channel_receive - fetch characters from a byte channel
31562306a36Sopenharmony_ci * @handle: byte channel handle
31662306a36Sopenharmony_ci * @count: (input) max num of chars to receive, (output) num chars received
31762306a36Sopenharmony_ci * @buffer: pointer to a 16-byte buffer
31862306a36Sopenharmony_ci *
31962306a36Sopenharmony_ci * The size of @buffer must be at least 16 bytes, even if you request fewer
32062306a36Sopenharmony_ci * than 16 characters, because we always write 16 bytes to @buffer.  This is
32162306a36Sopenharmony_ci * for performance reasons.
32262306a36Sopenharmony_ci *
32362306a36Sopenharmony_ci * Returns 0 for success, or an error code.
32462306a36Sopenharmony_ci */
32562306a36Sopenharmony_cistatic inline unsigned int ev_byte_channel_receive(unsigned int handle,
32662306a36Sopenharmony_ci	unsigned int *count, char buffer[EV_BYTE_CHANNEL_MAX_BYTES])
32762306a36Sopenharmony_ci{
32862306a36Sopenharmony_ci	register uintptr_t r11 __asm__("r11");
32962306a36Sopenharmony_ci	register uintptr_t r3 __asm__("r3");
33062306a36Sopenharmony_ci	register uintptr_t r4 __asm__("r4");
33162306a36Sopenharmony_ci	register uintptr_t r5 __asm__("r5");
33262306a36Sopenharmony_ci	register uintptr_t r6 __asm__("r6");
33362306a36Sopenharmony_ci	register uintptr_t r7 __asm__("r7");
33462306a36Sopenharmony_ci	register uintptr_t r8 __asm__("r8");
33562306a36Sopenharmony_ci	uint32_t *p = (uint32_t *) buffer;
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	r11 = EV_HCALL_TOKEN(EV_BYTE_CHANNEL_RECEIVE);
33862306a36Sopenharmony_ci	r3 = handle;
33962306a36Sopenharmony_ci	r4 = *count;
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	asm volatile("bl	epapr_hypercall_start"
34262306a36Sopenharmony_ci		: "+r" (r11), "+r" (r3), "+r" (r4),
34362306a36Sopenharmony_ci		  "=r" (r5), "=r" (r6), "=r" (r7), "=r" (r8)
34462306a36Sopenharmony_ci		: : EV_HCALL_CLOBBERS6
34562306a36Sopenharmony_ci	);
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	*count = r4;
34862306a36Sopenharmony_ci	p[0] = cpu_to_be32(r5);
34962306a36Sopenharmony_ci	p[1] = cpu_to_be32(r6);
35062306a36Sopenharmony_ci	p[2] = cpu_to_be32(r7);
35162306a36Sopenharmony_ci	p[3] = cpu_to_be32(r8);
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	return r3;
35462306a36Sopenharmony_ci}
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci/**
35762306a36Sopenharmony_ci * ev_byte_channel_poll - returns the status of the byte channel buffers
35862306a36Sopenharmony_ci * @handle: byte channel handle
35962306a36Sopenharmony_ci * @rx_count: returned count of bytes in receive queue
36062306a36Sopenharmony_ci * @tx_count: returned count of free space in transmit queue
36162306a36Sopenharmony_ci *
36262306a36Sopenharmony_ci * This function reports the amount of data in the receive queue (i.e. the
36362306a36Sopenharmony_ci * number of bytes you can read), and the amount of free space in the transmit
36462306a36Sopenharmony_ci * queue (i.e. the number of bytes you can write).
36562306a36Sopenharmony_ci *
36662306a36Sopenharmony_ci * Returns 0 for success, or an error code.
36762306a36Sopenharmony_ci */
36862306a36Sopenharmony_cistatic inline unsigned int ev_byte_channel_poll(unsigned int handle,
36962306a36Sopenharmony_ci	unsigned int *rx_count,	unsigned int *tx_count)
37062306a36Sopenharmony_ci{
37162306a36Sopenharmony_ci	register uintptr_t r11 __asm__("r11");
37262306a36Sopenharmony_ci	register uintptr_t r3 __asm__("r3");
37362306a36Sopenharmony_ci	register uintptr_t r4 __asm__("r4");
37462306a36Sopenharmony_ci	register uintptr_t r5 __asm__("r5");
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	r11 = EV_HCALL_TOKEN(EV_BYTE_CHANNEL_POLL);
37762306a36Sopenharmony_ci	r3 = handle;
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	asm volatile("bl	epapr_hypercall_start"
38062306a36Sopenharmony_ci		: "+r" (r11), "+r" (r3), "=r" (r4), "=r" (r5)
38162306a36Sopenharmony_ci		: : EV_HCALL_CLOBBERS3
38262306a36Sopenharmony_ci	);
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	*rx_count = r4;
38562306a36Sopenharmony_ci	*tx_count = r5;
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	return r3;
38862306a36Sopenharmony_ci}
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci/**
39162306a36Sopenharmony_ci * ev_int_iack - acknowledge an interrupt
39262306a36Sopenharmony_ci * @handle: handle to the target interrupt controller
39362306a36Sopenharmony_ci * @vector: returned interrupt vector
39462306a36Sopenharmony_ci *
39562306a36Sopenharmony_ci * If handle is zero, the function returns the next interrupt source
39662306a36Sopenharmony_ci * number to be handled irrespective of the hierarchy or cascading
39762306a36Sopenharmony_ci * of interrupt controllers. If non-zero, specifies a handle to the
39862306a36Sopenharmony_ci * interrupt controller that is the target of the acknowledge.
39962306a36Sopenharmony_ci *
40062306a36Sopenharmony_ci * Returns 0 for success, or an error code.
40162306a36Sopenharmony_ci */
40262306a36Sopenharmony_cistatic inline unsigned int ev_int_iack(unsigned int handle,
40362306a36Sopenharmony_ci	unsigned int *vector)
40462306a36Sopenharmony_ci{
40562306a36Sopenharmony_ci	register uintptr_t r11 __asm__("r11");
40662306a36Sopenharmony_ci	register uintptr_t r3 __asm__("r3");
40762306a36Sopenharmony_ci	register uintptr_t r4 __asm__("r4");
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	r11 = EV_HCALL_TOKEN(EV_INT_IACK);
41062306a36Sopenharmony_ci	r3 = handle;
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	asm volatile("bl	epapr_hypercall_start"
41362306a36Sopenharmony_ci		: "+r" (r11), "+r" (r3), "=r" (r4)
41462306a36Sopenharmony_ci		: : EV_HCALL_CLOBBERS2
41562306a36Sopenharmony_ci	);
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	*vector = r4;
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	return r3;
42062306a36Sopenharmony_ci}
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci/**
42362306a36Sopenharmony_ci * ev_doorbell_send - send a doorbell to another partition
42462306a36Sopenharmony_ci * @handle: doorbell send handle
42562306a36Sopenharmony_ci *
42662306a36Sopenharmony_ci * Returns 0 for success, or an error code.
42762306a36Sopenharmony_ci */
42862306a36Sopenharmony_cistatic inline unsigned int ev_doorbell_send(unsigned int handle)
42962306a36Sopenharmony_ci{
43062306a36Sopenharmony_ci	register uintptr_t r11 __asm__("r11");
43162306a36Sopenharmony_ci	register uintptr_t r3 __asm__("r3");
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	r11 = EV_HCALL_TOKEN(EV_DOORBELL_SEND);
43462306a36Sopenharmony_ci	r3 = handle;
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	asm volatile("bl	epapr_hypercall_start"
43762306a36Sopenharmony_ci		: "+r" (r11), "+r" (r3)
43862306a36Sopenharmony_ci		: : EV_HCALL_CLOBBERS1
43962306a36Sopenharmony_ci	);
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	return r3;
44262306a36Sopenharmony_ci}
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci/**
44562306a36Sopenharmony_ci * ev_idle -- wait for next interrupt on this core
44662306a36Sopenharmony_ci *
44762306a36Sopenharmony_ci * Returns 0 for success, or an error code.
44862306a36Sopenharmony_ci */
44962306a36Sopenharmony_cistatic inline unsigned int ev_idle(void)
45062306a36Sopenharmony_ci{
45162306a36Sopenharmony_ci	register uintptr_t r11 __asm__("r11");
45262306a36Sopenharmony_ci	register uintptr_t r3 __asm__("r3");
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	r11 = EV_HCALL_TOKEN(EV_IDLE);
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	asm volatile("bl	epapr_hypercall_start"
45762306a36Sopenharmony_ci		: "+r" (r11), "=r" (r3)
45862306a36Sopenharmony_ci		: : EV_HCALL_CLOBBERS1
45962306a36Sopenharmony_ci	);
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	return r3;
46262306a36Sopenharmony_ci}
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci#ifdef CONFIG_EPAPR_PARAVIRT
46562306a36Sopenharmony_cistatic inline unsigned long epapr_hypercall(unsigned long *in,
46662306a36Sopenharmony_ci			    unsigned long *out,
46762306a36Sopenharmony_ci			    unsigned long nr)
46862306a36Sopenharmony_ci{
46962306a36Sopenharmony_ci	register unsigned long r0 asm("r0");
47062306a36Sopenharmony_ci	register unsigned long r3 asm("r3") = in[0];
47162306a36Sopenharmony_ci	register unsigned long r4 asm("r4") = in[1];
47262306a36Sopenharmony_ci	register unsigned long r5 asm("r5") = in[2];
47362306a36Sopenharmony_ci	register unsigned long r6 asm("r6") = in[3];
47462306a36Sopenharmony_ci	register unsigned long r7 asm("r7") = in[4];
47562306a36Sopenharmony_ci	register unsigned long r8 asm("r8") = in[5];
47662306a36Sopenharmony_ci	register unsigned long r9 asm("r9") = in[6];
47762306a36Sopenharmony_ci	register unsigned long r10 asm("r10") = in[7];
47862306a36Sopenharmony_ci	register unsigned long r11 asm("r11") = nr;
47962306a36Sopenharmony_ci	register unsigned long r12 asm("r12");
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci	asm volatile("bl	epapr_hypercall_start"
48262306a36Sopenharmony_ci		     : "=r"(r0), "=r"(r3), "=r"(r4), "=r"(r5), "=r"(r6),
48362306a36Sopenharmony_ci		       "=r"(r7), "=r"(r8), "=r"(r9), "=r"(r10), "=r"(r11),
48462306a36Sopenharmony_ci		       "=r"(r12)
48562306a36Sopenharmony_ci		     : "r"(r3), "r"(r4), "r"(r5), "r"(r6), "r"(r7), "r"(r8),
48662306a36Sopenharmony_ci		       "r"(r9), "r"(r10), "r"(r11)
48762306a36Sopenharmony_ci		     : "memory", "cc", "xer", "ctr", "lr");
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	out[0] = r4;
49062306a36Sopenharmony_ci	out[1] = r5;
49162306a36Sopenharmony_ci	out[2] = r6;
49262306a36Sopenharmony_ci	out[3] = r7;
49362306a36Sopenharmony_ci	out[4] = r8;
49462306a36Sopenharmony_ci	out[5] = r9;
49562306a36Sopenharmony_ci	out[6] = r10;
49662306a36Sopenharmony_ci	out[7] = r11;
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	return r3;
49962306a36Sopenharmony_ci}
50062306a36Sopenharmony_ci#else
50162306a36Sopenharmony_cistatic unsigned long epapr_hypercall(unsigned long *in,
50262306a36Sopenharmony_ci				   unsigned long *out,
50362306a36Sopenharmony_ci				   unsigned long nr)
50462306a36Sopenharmony_ci{
50562306a36Sopenharmony_ci	return EV_UNIMPLEMENTED;
50662306a36Sopenharmony_ci}
50762306a36Sopenharmony_ci#endif
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_cistatic inline long epapr_hypercall0_1(unsigned int nr, unsigned long *r2)
51062306a36Sopenharmony_ci{
51162306a36Sopenharmony_ci	unsigned long in[8] = {0};
51262306a36Sopenharmony_ci	unsigned long out[8];
51362306a36Sopenharmony_ci	unsigned long r;
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	r = epapr_hypercall(in, out, nr);
51662306a36Sopenharmony_ci	*r2 = out[0];
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	return r;
51962306a36Sopenharmony_ci}
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_cistatic inline long epapr_hypercall0(unsigned int nr)
52262306a36Sopenharmony_ci{
52362306a36Sopenharmony_ci	unsigned long in[8] = {0};
52462306a36Sopenharmony_ci	unsigned long out[8];
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	return epapr_hypercall(in, out, nr);
52762306a36Sopenharmony_ci}
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_cistatic inline long epapr_hypercall1(unsigned int nr, unsigned long p1)
53062306a36Sopenharmony_ci{
53162306a36Sopenharmony_ci	unsigned long in[8] = {0};
53262306a36Sopenharmony_ci	unsigned long out[8];
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	in[0] = p1;
53562306a36Sopenharmony_ci	return epapr_hypercall(in, out, nr);
53662306a36Sopenharmony_ci}
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_cistatic inline long epapr_hypercall2(unsigned int nr, unsigned long p1,
53962306a36Sopenharmony_ci				    unsigned long p2)
54062306a36Sopenharmony_ci{
54162306a36Sopenharmony_ci	unsigned long in[8] = {0};
54262306a36Sopenharmony_ci	unsigned long out[8];
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	in[0] = p1;
54562306a36Sopenharmony_ci	in[1] = p2;
54662306a36Sopenharmony_ci	return epapr_hypercall(in, out, nr);
54762306a36Sopenharmony_ci}
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_cistatic inline long epapr_hypercall3(unsigned int nr, unsigned long p1,
55062306a36Sopenharmony_ci				    unsigned long p2, unsigned long p3)
55162306a36Sopenharmony_ci{
55262306a36Sopenharmony_ci	unsigned long in[8] = {0};
55362306a36Sopenharmony_ci	unsigned long out[8];
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	in[0] = p1;
55662306a36Sopenharmony_ci	in[1] = p2;
55762306a36Sopenharmony_ci	in[2] = p3;
55862306a36Sopenharmony_ci	return epapr_hypercall(in, out, nr);
55962306a36Sopenharmony_ci}
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_cistatic inline long epapr_hypercall4(unsigned int nr, unsigned long p1,
56262306a36Sopenharmony_ci				    unsigned long p2, unsigned long p3,
56362306a36Sopenharmony_ci				    unsigned long p4)
56462306a36Sopenharmony_ci{
56562306a36Sopenharmony_ci	unsigned long in[8] = {0};
56662306a36Sopenharmony_ci	unsigned long out[8];
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	in[0] = p1;
56962306a36Sopenharmony_ci	in[1] = p2;
57062306a36Sopenharmony_ci	in[2] = p3;
57162306a36Sopenharmony_ci	in[3] = p4;
57262306a36Sopenharmony_ci	return epapr_hypercall(in, out, nr);
57362306a36Sopenharmony_ci}
57462306a36Sopenharmony_ci#endif /* !__ASSEMBLY__ */
57562306a36Sopenharmony_ci#endif /* _EPAPR_HCALLS_H */
576