xref: /openbmc/linux/drivers/misc/sgi-xp/xpc.h (revision e17d416b)
145d9ca49SDean Nelson /*
245d9ca49SDean Nelson  * This file is subject to the terms and conditions of the GNU General Public
345d9ca49SDean Nelson  * License.  See the file "COPYING" in the main directory of this archive
445d9ca49SDean Nelson  * for more details.
545d9ca49SDean Nelson  *
645d9ca49SDean Nelson  * Copyright (c) 2004-2008 Silicon Graphics, Inc.  All Rights Reserved.
745d9ca49SDean Nelson  */
845d9ca49SDean Nelson 
945d9ca49SDean Nelson /*
1045d9ca49SDean Nelson  * Cross Partition Communication (XPC) structures and macros.
1145d9ca49SDean Nelson  */
1245d9ca49SDean Nelson 
1345d9ca49SDean Nelson #ifndef _DRIVERS_MISC_SGIXP_XPC_H
1445d9ca49SDean Nelson #define _DRIVERS_MISC_SGIXP_XPC_H
1545d9ca49SDean Nelson 
1645d9ca49SDean Nelson #include <linux/interrupt.h>
1745d9ca49SDean Nelson #include <linux/sysctl.h>
1845d9ca49SDean Nelson #include <linux/device.h>
1945d9ca49SDean Nelson #include <linux/mutex.h>
2045d9ca49SDean Nelson #include <linux/completion.h>
2145d9ca49SDean Nelson #include <asm/pgtable.h>
2245d9ca49SDean Nelson #include <asm/processor.h>
2345d9ca49SDean Nelson #include <asm/sn/clksupport.h>
2445d9ca49SDean Nelson #include <asm/sn/addrs.h>
2545d9ca49SDean Nelson #include <asm/sn/mspec.h>
2645d9ca49SDean Nelson #include <asm/sn/shub_mmr.h>
2745d9ca49SDean Nelson #include "xp.h"
2845d9ca49SDean Nelson 
2945d9ca49SDean Nelson /*
3045d9ca49SDean Nelson  * XPC Version numbers consist of a major and minor number. XPC can always
3145d9ca49SDean Nelson  * talk to versions with same major #, and never talk to versions with a
3245d9ca49SDean Nelson  * different major #.
3345d9ca49SDean Nelson  */
3445d9ca49SDean Nelson #define _XPC_VERSION(_maj, _min)	(((_maj) << 4) | ((_min) & 0xf))
3545d9ca49SDean Nelson #define XPC_VERSION_MAJOR(_v)		((_v) >> 4)
3645d9ca49SDean Nelson #define XPC_VERSION_MINOR(_v)		((_v) & 0xf)
3745d9ca49SDean Nelson 
3845d9ca49SDean Nelson /*
3945d9ca49SDean Nelson  * The next macros define word or bit representations for given
4045d9ca49SDean Nelson  * C-brick nasid in either the SAL provided bit array representing
4145d9ca49SDean Nelson  * nasids in the partition/machine or the AMO_t array used for
4245d9ca49SDean Nelson  * inter-partition initiation communications.
4345d9ca49SDean Nelson  *
4445d9ca49SDean Nelson  * For SN2 machines, C-Bricks are alway even numbered NASIDs.  As
4545d9ca49SDean Nelson  * such, some space will be saved by insisting that nasid information
4645d9ca49SDean Nelson  * passed from SAL always be packed for C-Bricks and the
4745d9ca49SDean Nelson  * cross-partition interrupts use the same packing scheme.
4845d9ca49SDean Nelson  */
4945d9ca49SDean Nelson #define XPC_NASID_W_INDEX(_n)	(((_n) / 64) / 2)
5045d9ca49SDean Nelson #define XPC_NASID_B_INDEX(_n)	(((_n) / 2) & (64 - 1))
5145d9ca49SDean Nelson #define XPC_NASID_IN_ARRAY(_n, _p) ((_p)[XPC_NASID_W_INDEX(_n)] & \
5245d9ca49SDean Nelson 				    (1UL << XPC_NASID_B_INDEX(_n)))
5345d9ca49SDean Nelson #define XPC_NASID_FROM_W_B(_w, _b) (((_w) * 64 + (_b)) * 2)
5445d9ca49SDean Nelson 
5545d9ca49SDean Nelson #define XPC_HB_DEFAULT_INTERVAL		5	/* incr HB every x secs */
5645d9ca49SDean Nelson #define XPC_HB_CHECK_DEFAULT_INTERVAL	20	/* check HB every x secs */
5745d9ca49SDean Nelson 
5845d9ca49SDean Nelson /* define the process name of HB checker and the CPU it is pinned to */
5945d9ca49SDean Nelson #define XPC_HB_CHECK_THREAD_NAME	"xpc_hb"
6045d9ca49SDean Nelson #define XPC_HB_CHECK_CPU		0
6145d9ca49SDean Nelson 
6245d9ca49SDean Nelson /* define the process name of the discovery thread */
6345d9ca49SDean Nelson #define XPC_DISCOVERY_THREAD_NAME	"xpc_discovery"
6445d9ca49SDean Nelson 
6545d9ca49SDean Nelson /*
6645d9ca49SDean Nelson  * the reserved page
6745d9ca49SDean Nelson  *
6845d9ca49SDean Nelson  *   SAL reserves one page of memory per partition for XPC. Though a full page
6945d9ca49SDean Nelson  *   in length (16384 bytes), its starting address is not page aligned, but it
7045d9ca49SDean Nelson  *   is cacheline aligned. The reserved page consists of the following:
7145d9ca49SDean Nelson  *
7245d9ca49SDean Nelson  *   reserved page header
7345d9ca49SDean Nelson  *
7494bd2708SDean Nelson  *     The first two 64-byte cachelines of the reserved page contain the
7594bd2708SDean Nelson  *     header (struct xpc_rsvd_page). Before SAL initialization has completed,
7645d9ca49SDean Nelson  *     SAL has set up the following fields of the reserved page header:
7794bd2708SDean Nelson  *     SAL_signature, SAL_version, SAL_partid, and SAL_nasids_size. The
7894bd2708SDean Nelson  *     other fields are set up by XPC. (xpc_rsvd_page points to the local
7945d9ca49SDean Nelson  *     partition's reserved page.)
8045d9ca49SDean Nelson  *
8145d9ca49SDean Nelson  *   part_nasids mask
8245d9ca49SDean Nelson  *   mach_nasids mask
8345d9ca49SDean Nelson  *
8445d9ca49SDean Nelson  *     SAL also sets up two bitmaps (or masks), one that reflects the actual
8545d9ca49SDean Nelson  *     nasids in this partition (part_nasids), and the other that reflects
8645d9ca49SDean Nelson  *     the actual nasids in the entire machine (mach_nasids). We're only
8745d9ca49SDean Nelson  *     interested in the even numbered nasids (which contain the processors
8845d9ca49SDean Nelson  *     and/or memory), so we only need half as many bits to represent the
8945d9ca49SDean Nelson  *     nasids. The part_nasids mask is located starting at the first cacheline
9045d9ca49SDean Nelson  *     following the reserved page header. The mach_nasids mask follows right
9145d9ca49SDean Nelson  *     after the part_nasids mask. The size in bytes of each mask is reflected
9294bd2708SDean Nelson  *     by the reserved page header field 'SAL_nasids_size'. (Local partition's
9345d9ca49SDean Nelson  *     mask pointers are xpc_part_nasids and xpc_mach_nasids.)
9445d9ca49SDean Nelson  *
9594bd2708SDean Nelson  *   vars	(ia64-sn2 only)
9694bd2708SDean Nelson  *   vars part	(ia64-sn2 only)
9745d9ca49SDean Nelson  *
9845d9ca49SDean Nelson  *     Immediately following the mach_nasids mask are the XPC variables
9945d9ca49SDean Nelson  *     required by other partitions. First are those that are generic to all
10045d9ca49SDean Nelson  *     partitions (vars), followed on the next available cacheline by those
10145d9ca49SDean Nelson  *     which are partition specific (vars part). These are setup by XPC.
10245d9ca49SDean Nelson  *     (Local partition's vars pointers are xpc_vars and xpc_vars_part.)
10345d9ca49SDean Nelson  *
10494bd2708SDean Nelson  * Note: Until 'stamp' is set non-zero, the partition XPC code has not been
10594bd2708SDean Nelson  *       initialized.
10645d9ca49SDean Nelson  */
10745d9ca49SDean Nelson struct xpc_rsvd_page {
10845d9ca49SDean Nelson 	u64 SAL_signature;	/* SAL: unique signature */
10945d9ca49SDean Nelson 	u64 SAL_version;	/* SAL: version */
11094bd2708SDean Nelson 	short SAL_partid;	/* SAL: partition ID */
11194bd2708SDean Nelson 	short max_npartitions;	/* value of XPC_MAX_PARTITIONS */
11245d9ca49SDean Nelson 	u8 version;
11394bd2708SDean Nelson 	u8 pad1[3];		/* align to next u64 in 1st 64-byte cacheline */
11494bd2708SDean Nelson 	union {
1152c2b94f9SDean Nelson 		u64 vars_pa;	/* physical address of struct xpc_vars */
11694bd2708SDean Nelson 		u64 activate_mq_gpa;	/* global phys address of activate_mq */
11794bd2708SDean Nelson 	} sn;
11845d9ca49SDean Nelson 	struct timespec stamp;	/* time when reserved page was setup by XPC */
11994bd2708SDean Nelson 	u64 pad2[9];		/* align to last u64 in 2nd 64-byte cacheline */
12094bd2708SDean Nelson 	u64 SAL_nasids_size;	/* SAL: size of each nasid mask in bytes */
12145d9ca49SDean Nelson };
12245d9ca49SDean Nelson 
12394bd2708SDean Nelson #define XPC_RP_VERSION _XPC_VERSION(2, 0) /* version 2.0 of the reserved page */
12445d9ca49SDean Nelson 
12545d9ca49SDean Nelson #define XPC_SUPPORTS_RP_STAMP(_version) \
12645d9ca49SDean Nelson 			(_version >= _XPC_VERSION(1, 1))
12745d9ca49SDean Nelson 
12894bd2708SDean Nelson #define ZERO_STAMP	((struct timespec){0, 0})
12945d9ca49SDean Nelson /*
13045d9ca49SDean Nelson  * compare stamps - the return value is:
13145d9ca49SDean Nelson  *
13245d9ca49SDean Nelson  *	< 0,	if stamp1 < stamp2
13345d9ca49SDean Nelson  *	= 0,	if stamp1 == stamp2
13445d9ca49SDean Nelson  *	> 0,	if stamp1 > stamp2
13545d9ca49SDean Nelson  */
13645d9ca49SDean Nelson static inline int
13745d9ca49SDean Nelson xpc_compare_stamps(struct timespec *stamp1, struct timespec *stamp2)
13845d9ca49SDean Nelson {
13945d9ca49SDean Nelson 	int ret;
14045d9ca49SDean Nelson 
1412c2b94f9SDean Nelson 	ret = stamp1->tv_sec - stamp2->tv_sec;
1422c2b94f9SDean Nelson 	if (ret == 0)
14345d9ca49SDean Nelson 		ret = stamp1->tv_nsec - stamp2->tv_nsec;
1442c2b94f9SDean Nelson 
14545d9ca49SDean Nelson 	return ret;
14645d9ca49SDean Nelson }
14745d9ca49SDean Nelson 
14845d9ca49SDean Nelson /*
14945d9ca49SDean Nelson  * Define the structures by which XPC variables can be exported to other
15045d9ca49SDean Nelson  * partitions. (There are two: struct xpc_vars and struct xpc_vars_part)
15145d9ca49SDean Nelson  */
15245d9ca49SDean Nelson 
15345d9ca49SDean Nelson /*
15445d9ca49SDean Nelson  * The following structure describes the partition generic variables
15545d9ca49SDean Nelson  * needed by other partitions in order to properly initialize.
15645d9ca49SDean Nelson  *
15745d9ca49SDean Nelson  * struct xpc_vars version number also applies to struct xpc_vars_part.
15845d9ca49SDean Nelson  * Changes to either structure and/or related functionality should be
15945d9ca49SDean Nelson  * reflected by incrementing either the major or minor version numbers
16045d9ca49SDean Nelson  * of struct xpc_vars.
16145d9ca49SDean Nelson  */
16245d9ca49SDean Nelson struct xpc_vars {
16345d9ca49SDean Nelson 	u8 version;
16445d9ca49SDean Nelson 	u64 heartbeat;
16545d9ca49SDean Nelson 	u64 heartbeating_to_mask;
16645d9ca49SDean Nelson 	u64 heartbeat_offline;	/* if 0, heartbeat should be changing */
16745d9ca49SDean Nelson 	int act_nasid;
16845d9ca49SDean Nelson 	int act_phys_cpuid;
16945d9ca49SDean Nelson 	u64 vars_part_pa;
17045d9ca49SDean Nelson 	u64 amos_page_pa;	/* paddr of page of AMOs from MSPEC driver */
17145d9ca49SDean Nelson 	AMO_t *amos_page;	/* vaddr of page of AMOs from MSPEC driver */
17245d9ca49SDean Nelson };
17345d9ca49SDean Nelson 
17445d9ca49SDean Nelson #define XPC_V_VERSION _XPC_VERSION(3, 1)    /* version 3.1 of the cross vars */
17545d9ca49SDean Nelson 
17645d9ca49SDean Nelson #define XPC_SUPPORTS_DISENGAGE_REQUEST(_version) \
17745d9ca49SDean Nelson 			(_version >= _XPC_VERSION(3, 1))
17845d9ca49SDean Nelson 
17945d9ca49SDean Nelson static inline int
18064d032baSDean Nelson xpc_hb_allowed(short partid, struct xpc_vars *vars)
18145d9ca49SDean Nelson {
18245d9ca49SDean Nelson 	return ((vars->heartbeating_to_mask & (1UL << partid)) != 0);
18345d9ca49SDean Nelson }
18445d9ca49SDean Nelson 
18545d9ca49SDean Nelson static inline void
18664d032baSDean Nelson xpc_allow_hb(short partid, struct xpc_vars *vars)
18745d9ca49SDean Nelson {
18845d9ca49SDean Nelson 	u64 old_mask, new_mask;
18945d9ca49SDean Nelson 
19045d9ca49SDean Nelson 	do {
19145d9ca49SDean Nelson 		old_mask = vars->heartbeating_to_mask;
19245d9ca49SDean Nelson 		new_mask = (old_mask | (1UL << partid));
19345d9ca49SDean Nelson 	} while (cmpxchg(&vars->heartbeating_to_mask, old_mask, new_mask) !=
19445d9ca49SDean Nelson 		 old_mask);
19545d9ca49SDean Nelson }
19645d9ca49SDean Nelson 
19745d9ca49SDean Nelson static inline void
19864d032baSDean Nelson xpc_disallow_hb(short partid, struct xpc_vars *vars)
19945d9ca49SDean Nelson {
20045d9ca49SDean Nelson 	u64 old_mask, new_mask;
20145d9ca49SDean Nelson 
20245d9ca49SDean Nelson 	do {
20345d9ca49SDean Nelson 		old_mask = vars->heartbeating_to_mask;
20445d9ca49SDean Nelson 		new_mask = (old_mask & ~(1UL << partid));
20545d9ca49SDean Nelson 	} while (cmpxchg(&vars->heartbeating_to_mask, old_mask, new_mask) !=
20645d9ca49SDean Nelson 		 old_mask);
20745d9ca49SDean Nelson }
20845d9ca49SDean Nelson 
20945d9ca49SDean Nelson /*
21045d9ca49SDean Nelson  * The AMOs page consists of a number of AMO variables which are divided into
21145d9ca49SDean Nelson  * four groups, The first two groups are used to identify an IRQ's sender.
21245d9ca49SDean Nelson  * These two groups consist of 64 and 128 AMO variables respectively. The last
21345d9ca49SDean Nelson  * two groups, consisting of just one AMO variable each, are used to identify
21445d9ca49SDean Nelson  * the remote partitions that are currently engaged (from the viewpoint of
21545d9ca49SDean Nelson  * the XPC running on the remote partition).
21645d9ca49SDean Nelson  */
21745d9ca49SDean Nelson #define XPC_NOTIFY_IRQ_AMOS	   0
218bc63d387SDean Nelson #define XPC_ACTIVATE_IRQ_AMOS	   (XPC_NOTIFY_IRQ_AMOS + XP_MAX_NPARTITIONS_SN2)
21945d9ca49SDean Nelson #define XPC_ENGAGED_PARTITIONS_AMO (XPC_ACTIVATE_IRQ_AMOS + XP_NASID_MASK_WORDS)
22045d9ca49SDean Nelson #define XPC_DISENGAGE_REQUEST_AMO  (XPC_ENGAGED_PARTITIONS_AMO + 1)
22145d9ca49SDean Nelson 
22245d9ca49SDean Nelson /*
22345d9ca49SDean Nelson  * The following structure describes the per partition specific variables.
22445d9ca49SDean Nelson  *
22545d9ca49SDean Nelson  * An array of these structures, one per partition, will be defined. As a
22645d9ca49SDean Nelson  * partition becomes active XPC will copy the array entry corresponding to
22794bd2708SDean Nelson  * itself from that partition. It is desirable that the size of this structure
22894bd2708SDean Nelson  * evenly divides into a 128-byte cacheline, such that none of the entries in
22994bd2708SDean Nelson  * this array crosses a 128-byte cacheline boundary. As it is now, each entry
230e17d416bSDean Nelson  * occupies 64-bytes.
23145d9ca49SDean Nelson  */
232e17d416bSDean Nelson struct xpc_vars_part_sn2 {
2332c2b94f9SDean Nelson 	u64 magic;
23445d9ca49SDean Nelson 
23545d9ca49SDean Nelson 	u64 openclose_args_pa;	/* physical address of open and close args */
23645d9ca49SDean Nelson 	u64 GPs_pa;		/* physical address of Get/Put values */
23745d9ca49SDean Nelson 
23845d9ca49SDean Nelson 	u64 IPI_amo_pa;		/* physical address of IPI AMO_t structure */
23945d9ca49SDean Nelson 	int IPI_nasid;		/* nasid of where to send IPIs */
24045d9ca49SDean Nelson 	int IPI_phys_cpuid;	/* physical CPU ID of where to send IPIs */
24145d9ca49SDean Nelson 
24245d9ca49SDean Nelson 	u8 nchannels;		/* #of defined channels supported */
24345d9ca49SDean Nelson 
24445d9ca49SDean Nelson 	u8 reserved[23];	/* pad to a full 64 bytes */
24545d9ca49SDean Nelson };
24645d9ca49SDean Nelson 
24745d9ca49SDean Nelson /*
24845d9ca49SDean Nelson  * The vars_part MAGIC numbers play a part in the first contact protocol.
24945d9ca49SDean Nelson  *
25045d9ca49SDean Nelson  * MAGIC1 indicates that the per partition specific variables for a remote
25145d9ca49SDean Nelson  * partition have been initialized by this partition.
25245d9ca49SDean Nelson  *
25345d9ca49SDean Nelson  * MAGIC2 indicates that this partition has pulled the remote partititions
25445d9ca49SDean Nelson  * per partition variables that pertain to this partition.
25545d9ca49SDean Nelson  */
25645d9ca49SDean Nelson #define XPC_VP_MAGIC1	0x0053524156435058L   /* 'XPCVARS\0'L (little endian) */
25745d9ca49SDean Nelson #define XPC_VP_MAGIC2	0x0073726176435058L   /* 'XPCvars\0'L (little endian) */
25845d9ca49SDean Nelson 
25945d9ca49SDean Nelson /* the reserved page sizes and offsets */
26045d9ca49SDean Nelson 
26145d9ca49SDean Nelson #define XPC_RP_HEADER_SIZE	L1_CACHE_ALIGN(sizeof(struct xpc_rsvd_page))
26245d9ca49SDean Nelson #define XPC_RP_VARS_SIZE	L1_CACHE_ALIGN(sizeof(struct xpc_vars))
26345d9ca49SDean Nelson 
2642c2b94f9SDean Nelson #define XPC_RP_PART_NASIDS(_rp) ((u64 *)((u8 *)(_rp) + XPC_RP_HEADER_SIZE))
26545d9ca49SDean Nelson #define XPC_RP_MACH_NASIDS(_rp) (XPC_RP_PART_NASIDS(_rp) + xp_nasid_mask_words)
2662c2b94f9SDean Nelson #define XPC_RP_VARS(_rp)	((struct xpc_vars *)(XPC_RP_MACH_NASIDS(_rp) + \
2672c2b94f9SDean Nelson 				    xp_nasid_mask_words))
26845d9ca49SDean Nelson 
26945d9ca49SDean Nelson /*
27045d9ca49SDean Nelson  * Functions registered by add_timer() or called by kernel_thread() only
27145d9ca49SDean Nelson  * allow for a single 64-bit argument. The following macros can be used to
27245d9ca49SDean Nelson  * pack and unpack two (32-bit, 16-bit or 8-bit) arguments into or out from
27345d9ca49SDean Nelson  * the passed argument.
27445d9ca49SDean Nelson  */
27545d9ca49SDean Nelson #define XPC_PACK_ARGS(_arg1, _arg2) \
27645d9ca49SDean Nelson 			((((u64) _arg1) & 0xffffffff) | \
27745d9ca49SDean Nelson 			((((u64) _arg2) & 0xffffffff) << 32))
27845d9ca49SDean Nelson 
27945d9ca49SDean Nelson #define XPC_UNPACK_ARG1(_args)	(((u64) _args) & 0xffffffff)
28045d9ca49SDean Nelson #define XPC_UNPACK_ARG2(_args)	((((u64) _args) >> 32) & 0xffffffff)
28145d9ca49SDean Nelson 
28245d9ca49SDean Nelson /*
28345d9ca49SDean Nelson  * Define a Get/Put value pair (pointers) used with a message queue.
28445d9ca49SDean Nelson  */
28545d9ca49SDean Nelson struct xpc_gp {
2862c2b94f9SDean Nelson 	s64 get;		/* Get value */
2872c2b94f9SDean Nelson 	s64 put;		/* Put value */
28845d9ca49SDean Nelson };
28945d9ca49SDean Nelson 
29045d9ca49SDean Nelson #define XPC_GP_SIZE \
291bc63d387SDean Nelson 		L1_CACHE_ALIGN(sizeof(struct xpc_gp) * XPC_MAX_NCHANNELS)
29245d9ca49SDean Nelson 
29345d9ca49SDean Nelson /*
29445d9ca49SDean Nelson  * Define a structure that contains arguments associated with opening and
29545d9ca49SDean Nelson  * closing a channel.
29645d9ca49SDean Nelson  */
29745d9ca49SDean Nelson struct xpc_openclose_args {
29845d9ca49SDean Nelson 	u16 reason;		/* reason why channel is closing */
29945d9ca49SDean Nelson 	u16 msg_size;		/* sizeof each message entry */
30045d9ca49SDean Nelson 	u16 remote_nentries;	/* #of message entries in remote msg queue */
30145d9ca49SDean Nelson 	u16 local_nentries;	/* #of message entries in local msg queue */
30245d9ca49SDean Nelson 	u64 local_msgqueue_pa;	/* physical address of local message queue */
30345d9ca49SDean Nelson };
30445d9ca49SDean Nelson 
30545d9ca49SDean Nelson #define XPC_OPENCLOSE_ARGS_SIZE \
306bc63d387SDean Nelson 	      L1_CACHE_ALIGN(sizeof(struct xpc_openclose_args) * \
307bc63d387SDean Nelson 	      XPC_MAX_NCHANNELS)
30845d9ca49SDean Nelson 
30945d9ca49SDean Nelson /* struct xpc_msg flags */
31045d9ca49SDean Nelson 
31145d9ca49SDean Nelson #define	XPC_M_DONE		0x01	/* msg has been received/consumed */
31245d9ca49SDean Nelson #define	XPC_M_READY		0x02	/* msg is ready to be sent */
31345d9ca49SDean Nelson #define	XPC_M_INTERRUPT		0x04	/* send interrupt when msg consumed */
31445d9ca49SDean Nelson 
31545d9ca49SDean Nelson #define XPC_MSG_ADDRESS(_payload) \
31645d9ca49SDean Nelson 		((struct xpc_msg *)((u8 *)(_payload) - XPC_MSG_PAYLOAD_OFFSET))
31745d9ca49SDean Nelson 
31845d9ca49SDean Nelson /*
31945d9ca49SDean Nelson  * Defines notify entry.
32045d9ca49SDean Nelson  *
32145d9ca49SDean Nelson  * This is used to notify a message's sender that their message was received
32245d9ca49SDean Nelson  * and consumed by the intended recipient.
32345d9ca49SDean Nelson  */
32445d9ca49SDean Nelson struct xpc_notify {
3252c2b94f9SDean Nelson 	u8 type;		/* type of notification */
32645d9ca49SDean Nelson 
32745d9ca49SDean Nelson 	/* the following two fields are only used if type == XPC_N_CALL */
32845d9ca49SDean Nelson 	xpc_notify_func func;	/* user's notify function */
32945d9ca49SDean Nelson 	void *key;		/* pointer to user's key */
33045d9ca49SDean Nelson };
33145d9ca49SDean Nelson 
33245d9ca49SDean Nelson /* struct xpc_notify type of notification */
33345d9ca49SDean Nelson 
33445d9ca49SDean Nelson #define	XPC_N_CALL		0x01	/* notify function provided by user */
33545d9ca49SDean Nelson 
33645d9ca49SDean Nelson /*
33745d9ca49SDean Nelson  * Define the structure that manages all the stuff required by a channel. In
33845d9ca49SDean Nelson  * particular, they are used to manage the messages sent across the channel.
33945d9ca49SDean Nelson  *
34045d9ca49SDean Nelson  * This structure is private to a partition, and is NOT shared across the
34145d9ca49SDean Nelson  * partition boundary.
34245d9ca49SDean Nelson  *
34345d9ca49SDean Nelson  * There is an array of these structures for each remote partition. It is
34445d9ca49SDean Nelson  * allocated at the time a partition becomes active. The array contains one
34545d9ca49SDean Nelson  * of these structures for each potential channel connection to that partition.
34645d9ca49SDean Nelson  *
34745d9ca49SDean Nelson  * Each of these structures manages two message queues (circular buffers).
34845d9ca49SDean Nelson  * They are allocated at the time a channel connection is made. One of
34945d9ca49SDean Nelson  * these message queues (local_msgqueue) holds the locally created messages
35045d9ca49SDean Nelson  * that are destined for the remote partition. The other of these message
35145d9ca49SDean Nelson  * queues (remote_msgqueue) is a locally cached copy of the remote partition's
35245d9ca49SDean Nelson  * own local_msgqueue.
35345d9ca49SDean Nelson  *
35445d9ca49SDean Nelson  * The following is a description of the Get/Put pointers used to manage these
35545d9ca49SDean Nelson  * two message queues. Consider the local_msgqueue to be on one partition
35645d9ca49SDean Nelson  * and the remote_msgqueue to be its cached copy on another partition. A
35745d9ca49SDean Nelson  * description of what each of the lettered areas contains is included.
35845d9ca49SDean Nelson  *
35945d9ca49SDean Nelson  *
36045d9ca49SDean Nelson  *                     local_msgqueue      remote_msgqueue
36145d9ca49SDean Nelson  *
36245d9ca49SDean Nelson  *                        |/////////|      |/////////|
36345d9ca49SDean Nelson  *    w_remote_GP.get --> +---------+      |/////////|
36445d9ca49SDean Nelson  *                        |    F    |      |/////////|
36545d9ca49SDean Nelson  *     remote_GP.get  --> +---------+      +---------+ <-- local_GP->get
36645d9ca49SDean Nelson  *                        |         |      |         |
36745d9ca49SDean Nelson  *                        |         |      |    E    |
36845d9ca49SDean Nelson  *                        |         |      |         |
36945d9ca49SDean Nelson  *                        |         |      +---------+ <-- w_local_GP.get
37045d9ca49SDean Nelson  *                        |    B    |      |/////////|
37145d9ca49SDean Nelson  *                        |         |      |////D////|
37245d9ca49SDean Nelson  *                        |         |      |/////////|
37345d9ca49SDean Nelson  *                        |         |      +---------+ <-- w_remote_GP.put
37445d9ca49SDean Nelson  *                        |         |      |////C////|
37545d9ca49SDean Nelson  *      local_GP->put --> +---------+      +---------+ <-- remote_GP.put
37645d9ca49SDean Nelson  *                        |         |      |/////////|
37745d9ca49SDean Nelson  *                        |    A    |      |/////////|
37845d9ca49SDean Nelson  *                        |         |      |/////////|
37945d9ca49SDean Nelson  *     w_local_GP.put --> +---------+      |/////////|
38045d9ca49SDean Nelson  *                        |/////////|      |/////////|
38145d9ca49SDean Nelson  *
38245d9ca49SDean Nelson  *
38345d9ca49SDean Nelson  *	    ( remote_GP.[get|put] are cached copies of the remote
38445d9ca49SDean Nelson  *	      partition's local_GP->[get|put], and thus their values can
38545d9ca49SDean Nelson  *	      lag behind their counterparts on the remote partition. )
38645d9ca49SDean Nelson  *
38745d9ca49SDean Nelson  *
38845d9ca49SDean Nelson  *  A - Messages that have been allocated, but have not yet been sent to the
38945d9ca49SDean Nelson  *	remote partition.
39045d9ca49SDean Nelson  *
39145d9ca49SDean Nelson  *  B - Messages that have been sent, but have not yet been acknowledged by the
39245d9ca49SDean Nelson  *      remote partition as having been received.
39345d9ca49SDean Nelson  *
39445d9ca49SDean Nelson  *  C - Area that needs to be prepared for the copying of sent messages, by
39545d9ca49SDean Nelson  *	the clearing of the message flags of any previously received messages.
39645d9ca49SDean Nelson  *
39745d9ca49SDean Nelson  *  D - Area into which sent messages are to be copied from the remote
39845d9ca49SDean Nelson  *	partition's local_msgqueue and then delivered to their intended
39945d9ca49SDean Nelson  *	recipients. [ To allow for a multi-message copy, another pointer
40045d9ca49SDean Nelson  *	(next_msg_to_pull) has been added to keep track of the next message
40145d9ca49SDean Nelson  *	number needing to be copied (pulled). It chases after w_remote_GP.put.
40245d9ca49SDean Nelson  *	Any messages lying between w_local_GP.get and next_msg_to_pull have
40345d9ca49SDean Nelson  *	been copied and are ready to be delivered. ]
40445d9ca49SDean Nelson  *
40545d9ca49SDean Nelson  *  E - Messages that have been copied and delivered, but have not yet been
40645d9ca49SDean Nelson  *	acknowledged by the recipient as having been received.
40745d9ca49SDean Nelson  *
40845d9ca49SDean Nelson  *  F - Messages that have been acknowledged, but XPC has not yet notified the
40945d9ca49SDean Nelson  *	sender that the message was received by its intended recipient.
41045d9ca49SDean Nelson  *	This is also an area that needs to be prepared for the allocating of
41145d9ca49SDean Nelson  *	new messages, by the clearing of the message flags of the acknowledged
41245d9ca49SDean Nelson  *	messages.
41345d9ca49SDean Nelson  */
41445d9ca49SDean Nelson struct xpc_channel {
41564d032baSDean Nelson 	short partid;		/* ID of remote partition connected */
41645d9ca49SDean Nelson 	spinlock_t lock;	/* lock for updating this structure */
41745d9ca49SDean Nelson 	u32 flags;		/* general flags */
41845d9ca49SDean Nelson 
41965c17b80SDean Nelson 	enum xp_retval reason;	/* reason why channel is disconnect'g */
42045d9ca49SDean Nelson 	int reason_line;	/* line# disconnect initiated from */
42145d9ca49SDean Nelson 
42245d9ca49SDean Nelson 	u16 number;		/* channel # */
42345d9ca49SDean Nelson 
42445d9ca49SDean Nelson 	u16 msg_size;		/* sizeof each msg entry */
42545d9ca49SDean Nelson 	u16 local_nentries;	/* #of msg entries in local msg queue */
42645d9ca49SDean Nelson 	u16 remote_nentries;	/* #of msg entries in remote msg queue */
42745d9ca49SDean Nelson 
42845d9ca49SDean Nelson 	void *local_msgqueue_base;	/* base address of kmalloc'd space */
42945d9ca49SDean Nelson 	struct xpc_msg *local_msgqueue;	/* local message queue */
43045d9ca49SDean Nelson 	void *remote_msgqueue_base;	/* base address of kmalloc'd space */
43145d9ca49SDean Nelson 	struct xpc_msg *remote_msgqueue; /* cached copy of remote partition's */
43245d9ca49SDean Nelson 					 /* local message queue */
43345d9ca49SDean Nelson 	u64 remote_msgqueue_pa;	/* phys addr of remote partition's */
43445d9ca49SDean Nelson 				/* local message queue */
43545d9ca49SDean Nelson 
43645d9ca49SDean Nelson 	atomic_t references;	/* #of external references to queues */
43745d9ca49SDean Nelson 
43845d9ca49SDean Nelson 	atomic_t n_on_msg_allocate_wq;	/* #on msg allocation wait queue */
43945d9ca49SDean Nelson 	wait_queue_head_t msg_allocate_wq;	/* msg allocation wait queue */
44045d9ca49SDean Nelson 
44145d9ca49SDean Nelson 	u8 delayed_IPI_flags;	/* IPI flags received, but delayed */
44245d9ca49SDean Nelson 				/* action until channel disconnected */
44345d9ca49SDean Nelson 
44445d9ca49SDean Nelson 	/* queue of msg senders who want to be notified when msg received */
44545d9ca49SDean Nelson 
44645d9ca49SDean Nelson 	atomic_t n_to_notify;	/* #of msg senders to notify */
44745d9ca49SDean Nelson 	struct xpc_notify *notify_queue;    /* notify queue for messages sent */
44845d9ca49SDean Nelson 
44945d9ca49SDean Nelson 	xpc_channel_func func;	/* user's channel function */
45045d9ca49SDean Nelson 	void *key;		/* pointer to user's key */
45145d9ca49SDean Nelson 
45245d9ca49SDean Nelson 	struct mutex msg_to_pull_mutex;	/* next msg to pull serialization */
45345d9ca49SDean Nelson 	struct completion wdisconnect_wait;    /* wait for channel disconnect */
45445d9ca49SDean Nelson 
45545d9ca49SDean Nelson 	struct xpc_openclose_args *local_openclose_args; /* args passed on */
45645d9ca49SDean Nelson 					     /* opening or closing of channel */
45745d9ca49SDean Nelson 
45845d9ca49SDean Nelson 	/* various flavors of local and remote Get/Put values */
45945d9ca49SDean Nelson 
46045d9ca49SDean Nelson 	struct xpc_gp *local_GP;	/* local Get/Put values */
46145d9ca49SDean Nelson 	struct xpc_gp remote_GP;	/* remote Get/Put values */
46245d9ca49SDean Nelson 	struct xpc_gp w_local_GP;	/* working local Get/Put values */
46345d9ca49SDean Nelson 	struct xpc_gp w_remote_GP;	/* working remote Get/Put values */
46445d9ca49SDean Nelson 	s64 next_msg_to_pull;	/* Put value of next msg to pull */
46545d9ca49SDean Nelson 
46645d9ca49SDean Nelson 	/* kthread management related fields */
46745d9ca49SDean Nelson 
46845d9ca49SDean Nelson 	atomic_t kthreads_assigned;	/* #of kthreads assigned to channel */
46945d9ca49SDean Nelson 	u32 kthreads_assigned_limit;	/* limit on #of kthreads assigned */
47045d9ca49SDean Nelson 	atomic_t kthreads_idle;	/* #of kthreads idle waiting for work */
47145d9ca49SDean Nelson 	u32 kthreads_idle_limit;	/* limit on #of kthreads idle */
47245d9ca49SDean Nelson 	atomic_t kthreads_active;	/* #of kthreads actively working */
47345d9ca49SDean Nelson 
47445d9ca49SDean Nelson 	wait_queue_head_t idle_wq;	/* idle kthread wait queue */
47545d9ca49SDean Nelson 
47645d9ca49SDean Nelson } ____cacheline_aligned;
47745d9ca49SDean Nelson 
47845d9ca49SDean Nelson /* struct xpc_channel flags */
47945d9ca49SDean Nelson 
48045d9ca49SDean Nelson #define	XPC_C_WASCONNECTED	0x00000001	/* channel was connected */
48145d9ca49SDean Nelson 
48245d9ca49SDean Nelson #define	XPC_C_ROPENREPLY	0x00000002	/* remote open channel reply */
48345d9ca49SDean Nelson #define	XPC_C_OPENREPLY		0x00000004	/* local open channel reply */
48445d9ca49SDean Nelson #define	XPC_C_ROPENREQUEST	0x00000008     /* remote open channel request */
48545d9ca49SDean Nelson #define	XPC_C_OPENREQUEST	0x00000010	/* local open channel request */
48645d9ca49SDean Nelson 
48745d9ca49SDean Nelson #define	XPC_C_SETUP		0x00000020 /* channel's msgqueues are alloc'd */
48845d9ca49SDean Nelson #define	XPC_C_CONNECTEDCALLOUT	0x00000040     /* connected callout initiated */
48945d9ca49SDean Nelson #define	XPC_C_CONNECTEDCALLOUT_MADE \
49045d9ca49SDean Nelson 				0x00000080     /* connected callout completed */
49145d9ca49SDean Nelson #define	XPC_C_CONNECTED		0x00000100	/* local channel is connected */
49245d9ca49SDean Nelson #define	XPC_C_CONNECTING	0x00000200	/* channel is being connected */
49345d9ca49SDean Nelson 
49445d9ca49SDean Nelson #define	XPC_C_RCLOSEREPLY	0x00000400	/* remote close channel reply */
49545d9ca49SDean Nelson #define	XPC_C_CLOSEREPLY	0x00000800	/* local close channel reply */
49645d9ca49SDean Nelson #define	XPC_C_RCLOSEREQUEST	0x00001000    /* remote close channel request */
49745d9ca49SDean Nelson #define	XPC_C_CLOSEREQUEST	0x00002000     /* local close channel request */
49845d9ca49SDean Nelson 
49945d9ca49SDean Nelson #define	XPC_C_DISCONNECTED	0x00004000	/* channel is disconnected */
50045d9ca49SDean Nelson #define	XPC_C_DISCONNECTING	0x00008000   /* channel is being disconnected */
50145d9ca49SDean Nelson #define	XPC_C_DISCONNECTINGCALLOUT \
50245d9ca49SDean Nelson 				0x00010000 /* disconnecting callout initiated */
50345d9ca49SDean Nelson #define	XPC_C_DISCONNECTINGCALLOUT_MADE \
50445d9ca49SDean Nelson 				0x00020000 /* disconnecting callout completed */
50545d9ca49SDean Nelson #define	XPC_C_WDISCONNECT	0x00040000  /* waiting for channel disconnect */
50645d9ca49SDean Nelson 
50745d9ca49SDean Nelson /*
50845d9ca49SDean Nelson  * Manages channels on a partition basis. There is one of these structures
50945d9ca49SDean Nelson  * for each partition (a partition will never utilize the structure that
51045d9ca49SDean Nelson  * represents itself).
51145d9ca49SDean Nelson  */
51245d9ca49SDean Nelson struct xpc_partition {
51345d9ca49SDean Nelson 
51445d9ca49SDean Nelson 	/* XPC HB infrastructure */
51545d9ca49SDean Nelson 
51645d9ca49SDean Nelson 	u8 remote_rp_version;	/* version# of partition's rsvd pg */
51745d9ca49SDean Nelson 	struct timespec remote_rp_stamp; /* time when rsvd pg was initialized */
51845d9ca49SDean Nelson 	u64 remote_rp_pa;	/* phys addr of partition's rsvd pg */
51945d9ca49SDean Nelson 	u64 remote_vars_pa;	/* phys addr of partition's vars */
52045d9ca49SDean Nelson 	u64 remote_vars_part_pa;	/* phys addr of partition's vars part */
52145d9ca49SDean Nelson 	u64 last_heartbeat;	/* HB at last read */
52245d9ca49SDean Nelson 	u64 remote_amos_page_pa;	/* phys addr of partition's amos page */
52345d9ca49SDean Nelson 	int remote_act_nasid;	/* active part's act/deact nasid */
52445d9ca49SDean Nelson 	int remote_act_phys_cpuid;	/* active part's act/deact phys cpuid */
52545d9ca49SDean Nelson 	u32 act_IRQ_rcvd;	/* IRQs since activation */
52645d9ca49SDean Nelson 	spinlock_t act_lock;	/* protect updating of act_state */
52745d9ca49SDean Nelson 	u8 act_state;		/* from XPC HB viewpoint */
52845d9ca49SDean Nelson 	u8 remote_vars_version;	/* version# of partition's vars */
52965c17b80SDean Nelson 	enum xp_retval reason;	/* reason partition is deactivating */
53045d9ca49SDean Nelson 	int reason_line;	/* line# deactivation initiated from */
53145d9ca49SDean Nelson 	int reactivate_nasid;	/* nasid in partition to reactivate */
53245d9ca49SDean Nelson 
53345d9ca49SDean Nelson 	unsigned long disengage_request_timeout;	/* timeout in jiffies */
53445d9ca49SDean Nelson 	struct timer_list disengage_request_timer;
53545d9ca49SDean Nelson 
53645d9ca49SDean Nelson 	/* XPC infrastructure referencing and teardown control */
53745d9ca49SDean Nelson 
5382c2b94f9SDean Nelson 	u8 setup_state;		/* infrastructure setup state */
53945d9ca49SDean Nelson 	wait_queue_head_t teardown_wq;	/* kthread waiting to teardown infra */
54045d9ca49SDean Nelson 	atomic_t references;	/* #of references to infrastructure */
54145d9ca49SDean Nelson 
54245d9ca49SDean Nelson 	u8 nchannels;		/* #of defined channels supported */
54345d9ca49SDean Nelson 	atomic_t nchannels_active;  /* #of channels that are not DISCONNECTED */
54445d9ca49SDean Nelson 	atomic_t nchannels_engaged;  /* #of channels engaged with remote part */
54545d9ca49SDean Nelson 	struct xpc_channel *channels;	/* array of channel structures */
54645d9ca49SDean Nelson 
54745d9ca49SDean Nelson 	void *local_GPs_base;	/* base address of kmalloc'd space */
54845d9ca49SDean Nelson 	struct xpc_gp *local_GPs;	/* local Get/Put values */
54945d9ca49SDean Nelson 	void *remote_GPs_base;	/* base address of kmalloc'd space */
5502c2b94f9SDean Nelson 	struct xpc_gp *remote_GPs;	/* copy of remote partition's local */
5512c2b94f9SDean Nelson 					/* Get/Put values */
55245d9ca49SDean Nelson 	u64 remote_GPs_pa;	/* phys address of remote partition's local */
55345d9ca49SDean Nelson 				/* Get/Put values */
55445d9ca49SDean Nelson 
55545d9ca49SDean Nelson 	/* fields used to pass args when opening or closing a channel */
55645d9ca49SDean Nelson 
55745d9ca49SDean Nelson 	void *local_openclose_args_base;   /* base address of kmalloc'd space */
55845d9ca49SDean Nelson 	struct xpc_openclose_args *local_openclose_args;      /* local's args */
55945d9ca49SDean Nelson 	void *remote_openclose_args_base;  /* base address of kmalloc'd space */
56045d9ca49SDean Nelson 	struct xpc_openclose_args *remote_openclose_args; /* copy of remote's */
56145d9ca49SDean Nelson 							  /* args */
56245d9ca49SDean Nelson 	u64 remote_openclose_args_pa;	/* phys addr of remote's args */
56345d9ca49SDean Nelson 
56445d9ca49SDean Nelson 	/* IPI sending, receiving and handling related fields */
56545d9ca49SDean Nelson 
56645d9ca49SDean Nelson 	int remote_IPI_nasid;	/* nasid of where to send IPIs */
56745d9ca49SDean Nelson 	int remote_IPI_phys_cpuid;	/* phys CPU ID of where to send IPIs */
56845d9ca49SDean Nelson 	AMO_t *remote_IPI_amo_va;    /* address of remote IPI AMO_t structure */
56945d9ca49SDean Nelson 
57045d9ca49SDean Nelson 	AMO_t *local_IPI_amo_va;	/* address of IPI AMO_t structure */
57145d9ca49SDean Nelson 	u64 local_IPI_amo;	/* IPI amo flags yet to be handled */
57245d9ca49SDean Nelson 	char IPI_owner[8];	/* IPI owner's name */
57345d9ca49SDean Nelson 	struct timer_list dropped_IPI_timer;	/* dropped IPI timer */
57445d9ca49SDean Nelson 
57545d9ca49SDean Nelson 	spinlock_t IPI_lock;	/* IPI handler lock */
57645d9ca49SDean Nelson 
57745d9ca49SDean Nelson 	/* channel manager related fields */
57845d9ca49SDean Nelson 
57945d9ca49SDean Nelson 	atomic_t channel_mgr_requests;	/* #of requests to activate chan mgr */
58045d9ca49SDean Nelson 	wait_queue_head_t channel_mgr_wq;	/* channel mgr's wait queue */
58145d9ca49SDean Nelson 
58245d9ca49SDean Nelson } ____cacheline_aligned;
58345d9ca49SDean Nelson 
58445d9ca49SDean Nelson /* struct xpc_partition act_state values (for XPC HB) */
58545d9ca49SDean Nelson 
58645d9ca49SDean Nelson #define	XPC_P_INACTIVE		0x00	/* partition is not active */
58745d9ca49SDean Nelson #define XPC_P_ACTIVATION_REQ	0x01	/* created thread to activate */
58845d9ca49SDean Nelson #define XPC_P_ACTIVATING	0x02	/* activation thread started */
58945d9ca49SDean Nelson #define XPC_P_ACTIVE		0x03	/* xpc_partition_up() was called */
59045d9ca49SDean Nelson #define XPC_P_DEACTIVATING	0x04	/* partition deactivation initiated */
59145d9ca49SDean Nelson 
59245d9ca49SDean Nelson #define XPC_DEACTIVATE_PARTITION(_p, _reason) \
59345d9ca49SDean Nelson 			xpc_deactivate_partition(__LINE__, (_p), (_reason))
59445d9ca49SDean Nelson 
59545d9ca49SDean Nelson /* struct xpc_partition setup_state values */
59645d9ca49SDean Nelson 
59745d9ca49SDean Nelson #define XPC_P_UNSET		0x00	/* infrastructure was never setup */
59845d9ca49SDean Nelson #define XPC_P_SETUP		0x01	/* infrastructure is setup */
59945d9ca49SDean Nelson #define XPC_P_WTEARDOWN		0x02	/* waiting to teardown infrastructure */
60045d9ca49SDean Nelson #define XPC_P_TORNDOWN		0x03	/* infrastructure is torndown */
60145d9ca49SDean Nelson 
60245d9ca49SDean Nelson /*
60345d9ca49SDean Nelson  * struct xpc_partition IPI_timer #of seconds to wait before checking for
60445d9ca49SDean Nelson  * dropped IPIs. These occur whenever an IPI amo write doesn't complete until
60545d9ca49SDean Nelson  * after the IPI was received.
60645d9ca49SDean Nelson  */
607e17d416bSDean Nelson #define XPC_P_DROPPED_IPI_WAIT_INTERVAL	(0.25 * HZ)
60845d9ca49SDean Nelson 
60945d9ca49SDean Nelson /* number of seconds to wait for other partitions to disengage */
61045d9ca49SDean Nelson #define XPC_DISENGAGE_REQUEST_DEFAULT_TIMELIMIT	90
61145d9ca49SDean Nelson 
61245d9ca49SDean Nelson /* interval in seconds to print 'waiting disengagement' messages */
61345d9ca49SDean Nelson #define XPC_DISENGAGE_PRINTMSG_INTERVAL		10
61445d9ca49SDean Nelson 
61564d032baSDean Nelson #define XPC_PARTID(_p)	((short)((_p) - &xpc_partitions[0]))
61645d9ca49SDean Nelson 
61745d9ca49SDean Nelson /* found in xp_main.c */
61845d9ca49SDean Nelson extern struct xpc_registration xpc_registrations[];
61945d9ca49SDean Nelson 
62045d9ca49SDean Nelson /* found in xpc_main.c */
62145d9ca49SDean Nelson extern struct device *xpc_part;
62245d9ca49SDean Nelson extern struct device *xpc_chan;
62345d9ca49SDean Nelson extern int xpc_disengage_request_timelimit;
62445d9ca49SDean Nelson extern int xpc_disengage_request_timedout;
62545d9ca49SDean Nelson extern irqreturn_t xpc_notify_IRQ_handler(int, void *);
62645d9ca49SDean Nelson extern void xpc_dropped_IPI_check(struct xpc_partition *);
62745d9ca49SDean Nelson extern void xpc_activate_partition(struct xpc_partition *);
62845d9ca49SDean Nelson extern void xpc_activate_kthreads(struct xpc_channel *, int);
62945d9ca49SDean Nelson extern void xpc_create_kthreads(struct xpc_channel *, int, int);
63045d9ca49SDean Nelson extern void xpc_disconnect_wait(int);
63194bd2708SDean Nelson extern enum xp_retval (*xpc_rsvd_page_init) (struct xpc_rsvd_page *);
632e17d416bSDean Nelson extern enum xp_retval (*xpc_make_first_contact) (struct xpc_partition *);
633e17d416bSDean Nelson extern u64 (*xpc_get_IPI_flags) (struct xpc_partition *);
634e17d416bSDean Nelson extern struct xpc_msg *(*xpc_get_deliverable_msg) (struct xpc_channel *);
635e17d416bSDean Nelson extern enum xp_retval (*xpc_setup_infrastructure) (struct xpc_partition *);
636e17d416bSDean Nelson extern void (*xpc_teardown_infrastructure) (struct xpc_partition *);
63794bd2708SDean Nelson 
63894bd2708SDean Nelson /* found in xpc_sn2.c */
63994bd2708SDean Nelson extern void xpc_init_sn2(void);
64094bd2708SDean Nelson extern struct xpc_vars *xpc_vars;		/*>>> eliminate from here */
64194bd2708SDean Nelson 
64294bd2708SDean Nelson /* found in xpc_uv.c */
64394bd2708SDean Nelson extern void xpc_init_uv(void);
64494bd2708SDean Nelson 
64545d9ca49SDean Nelson /* found in xpc_partition.c */
64645d9ca49SDean Nelson extern int xpc_exiting;
64794bd2708SDean Nelson extern int xp_nasid_mask_words;
64845d9ca49SDean Nelson extern struct xpc_rsvd_page *xpc_rsvd_page;
649bc63d387SDean Nelson extern struct xpc_partition *xpc_partitions;
65045d9ca49SDean Nelson extern char *xpc_remote_copy_buffer;
65145d9ca49SDean Nelson extern void *xpc_remote_copy_buffer_base;
65245d9ca49SDean Nelson extern void *xpc_kmalloc_cacheline_aligned(size_t, gfp_t, void **);
65394bd2708SDean Nelson extern struct xpc_rsvd_page *xpc_setup_rsvd_page(void);
65445d9ca49SDean Nelson extern void xpc_allow_IPI_ops(void);
65545d9ca49SDean Nelson extern void xpc_restrict_IPI_ops(void);
65645d9ca49SDean Nelson extern int xpc_identify_act_IRQ_sender(void);
65745d9ca49SDean Nelson extern int xpc_partition_disengaged(struct xpc_partition *);
65865c17b80SDean Nelson extern enum xp_retval xpc_mark_partition_active(struct xpc_partition *);
65945d9ca49SDean Nelson extern void xpc_mark_partition_inactive(struct xpc_partition *);
66045d9ca49SDean Nelson extern void xpc_discovery(void);
66145d9ca49SDean Nelson extern void xpc_check_remote_hb(void);
66245d9ca49SDean Nelson extern void xpc_deactivate_partition(const int, struct xpc_partition *,
66365c17b80SDean Nelson 				     enum xp_retval);
66464d032baSDean Nelson extern enum xp_retval xpc_initiate_partid_to_nasids(short, void *);
66545d9ca49SDean Nelson 
66645d9ca49SDean Nelson /* found in xpc_channel.c */
667e17d416bSDean Nelson extern void *xpc_kzalloc_cacheline_aligned(size_t, gfp_t, void **);
66845d9ca49SDean Nelson extern void xpc_initiate_connect(int);
66945d9ca49SDean Nelson extern void xpc_initiate_disconnect(int);
67064d032baSDean Nelson extern enum xp_retval xpc_initiate_allocate(short, int, u32, void **);
67164d032baSDean Nelson extern enum xp_retval xpc_initiate_send(short, int, void *);
67264d032baSDean Nelson extern enum xp_retval xpc_initiate_send_notify(short, int, void *,
67345d9ca49SDean Nelson 					       xpc_notify_func, void *);
67464d032baSDean Nelson extern void xpc_initiate_received(short, int, void *);
67545d9ca49SDean Nelson extern void xpc_process_channel_activity(struct xpc_partition *);
67645d9ca49SDean Nelson extern void xpc_connected_callout(struct xpc_channel *);
67745d9ca49SDean Nelson extern void xpc_deliver_msg(struct xpc_channel *);
67845d9ca49SDean Nelson extern void xpc_disconnect_channel(const int, struct xpc_channel *,
67965c17b80SDean Nelson 				   enum xp_retval, unsigned long *);
68065c17b80SDean Nelson extern void xpc_disconnect_callout(struct xpc_channel *, enum xp_retval);
68165c17b80SDean Nelson extern void xpc_partition_going_down(struct xpc_partition *, enum xp_retval);
68245d9ca49SDean Nelson 
68345d9ca49SDean Nelson static inline void
68445d9ca49SDean Nelson xpc_wakeup_channel_mgr(struct xpc_partition *part)
68545d9ca49SDean Nelson {
6862c2b94f9SDean Nelson 	if (atomic_inc_return(&part->channel_mgr_requests) == 1)
68745d9ca49SDean Nelson 		wake_up(&part->channel_mgr_wq);
68845d9ca49SDean Nelson }
68945d9ca49SDean Nelson 
69045d9ca49SDean Nelson /*
69145d9ca49SDean Nelson  * These next two inlines are used to keep us from tearing down a channel's
69245d9ca49SDean Nelson  * msg queues while a thread may be referencing them.
69345d9ca49SDean Nelson  */
69445d9ca49SDean Nelson static inline void
69545d9ca49SDean Nelson xpc_msgqueue_ref(struct xpc_channel *ch)
69645d9ca49SDean Nelson {
69745d9ca49SDean Nelson 	atomic_inc(&ch->references);
69845d9ca49SDean Nelson }
69945d9ca49SDean Nelson 
70045d9ca49SDean Nelson static inline void
70145d9ca49SDean Nelson xpc_msgqueue_deref(struct xpc_channel *ch)
70245d9ca49SDean Nelson {
70345d9ca49SDean Nelson 	s32 refs = atomic_dec_return(&ch->references);
70445d9ca49SDean Nelson 
70545d9ca49SDean Nelson 	DBUG_ON(refs < 0);
7062c2b94f9SDean Nelson 	if (refs == 0)
70745d9ca49SDean Nelson 		xpc_wakeup_channel_mgr(&xpc_partitions[ch->partid]);
70845d9ca49SDean Nelson }
70945d9ca49SDean Nelson 
71045d9ca49SDean Nelson #define XPC_DISCONNECT_CHANNEL(_ch, _reason, _irqflgs) \
71145d9ca49SDean Nelson 		xpc_disconnect_channel(__LINE__, _ch, _reason, _irqflgs)
71245d9ca49SDean Nelson 
71345d9ca49SDean Nelson /*
71445d9ca49SDean Nelson  * These two inlines are used to keep us from tearing down a partition's
71545d9ca49SDean Nelson  * setup infrastructure while a thread may be referencing it.
71645d9ca49SDean Nelson  */
71745d9ca49SDean Nelson static inline void
71845d9ca49SDean Nelson xpc_part_deref(struct xpc_partition *part)
71945d9ca49SDean Nelson {
72045d9ca49SDean Nelson 	s32 refs = atomic_dec_return(&part->references);
72145d9ca49SDean Nelson 
72245d9ca49SDean Nelson 	DBUG_ON(refs < 0);
7232c2b94f9SDean Nelson 	if (refs == 0 && part->setup_state == XPC_P_WTEARDOWN)
72445d9ca49SDean Nelson 		wake_up(&part->teardown_wq);
72545d9ca49SDean Nelson }
72645d9ca49SDean Nelson 
72745d9ca49SDean Nelson static inline int
72845d9ca49SDean Nelson xpc_part_ref(struct xpc_partition *part)
72945d9ca49SDean Nelson {
73045d9ca49SDean Nelson 	int setup;
73145d9ca49SDean Nelson 
73245d9ca49SDean Nelson 	atomic_inc(&part->references);
73345d9ca49SDean Nelson 	setup = (part->setup_state == XPC_P_SETUP);
7342c2b94f9SDean Nelson 	if (!setup)
73545d9ca49SDean Nelson 		xpc_part_deref(part);
7362c2b94f9SDean Nelson 
73745d9ca49SDean Nelson 	return setup;
73845d9ca49SDean Nelson }
73945d9ca49SDean Nelson 
74045d9ca49SDean Nelson /*
74145d9ca49SDean Nelson  * The following macro is to be used for the setting of the reason and
74245d9ca49SDean Nelson  * reason_line fields in both the struct xpc_channel and struct xpc_partition
74345d9ca49SDean Nelson  * structures.
74445d9ca49SDean Nelson  */
74545d9ca49SDean Nelson #define XPC_SET_REASON(_p, _reason, _line) \
74645d9ca49SDean Nelson 	{ \
74745d9ca49SDean Nelson 		(_p)->reason = _reason; \
74845d9ca49SDean Nelson 		(_p)->reason_line = _line; \
74945d9ca49SDean Nelson 	}
75045d9ca49SDean Nelson 
75145d9ca49SDean Nelson /*
75245d9ca49SDean Nelson  * This next set of inlines are used to keep track of when a partition is
75345d9ca49SDean Nelson  * potentially engaged in accessing memory belonging to another partition.
75445d9ca49SDean Nelson  */
75545d9ca49SDean Nelson 
75645d9ca49SDean Nelson static inline void
75745d9ca49SDean Nelson xpc_mark_partition_engaged(struct xpc_partition *part)
75845d9ca49SDean Nelson {
75945d9ca49SDean Nelson 	unsigned long irq_flags;
76045d9ca49SDean Nelson 	AMO_t *amo = (AMO_t *)__va(part->remote_amos_page_pa +
7614a3ad2ddSDean Nelson 				   (XPC_ENGAGED_PARTITIONS_AMO *
7624a3ad2ddSDean Nelson 				    sizeof(AMO_t)));
76345d9ca49SDean Nelson 
76445d9ca49SDean Nelson 	local_irq_save(irq_flags);
76545d9ca49SDean Nelson 
76645d9ca49SDean Nelson 	/* set bit corresponding to our partid in remote partition's AMO */
76745d9ca49SDean Nelson 	FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_OR,
76845d9ca49SDean Nelson 			 (1UL << sn_partition_id));
76945d9ca49SDean Nelson 	/*
77045d9ca49SDean Nelson 	 * We must always use the nofault function regardless of whether we
77145d9ca49SDean Nelson 	 * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we
77245d9ca49SDean Nelson 	 * didn't, we'd never know that the other partition is down and would
77345d9ca49SDean Nelson 	 * keep sending IPIs and AMOs to it until the heartbeat times out.
77445d9ca49SDean Nelson 	 */
77545d9ca49SDean Nelson 	(void)xp_nofault_PIOR((u64 *)GLOBAL_MMR_ADDR(NASID_GET(&amo->
7764a3ad2ddSDean Nelson 							       variable),
7774a3ad2ddSDean Nelson 						     xp_nofault_PIOR_target));
77845d9ca49SDean Nelson 
77945d9ca49SDean Nelson 	local_irq_restore(irq_flags);
78045d9ca49SDean Nelson }
78145d9ca49SDean Nelson 
78245d9ca49SDean Nelson static inline void
78345d9ca49SDean Nelson xpc_mark_partition_disengaged(struct xpc_partition *part)
78445d9ca49SDean Nelson {
78545d9ca49SDean Nelson 	unsigned long irq_flags;
78645d9ca49SDean Nelson 	AMO_t *amo = (AMO_t *)__va(part->remote_amos_page_pa +
7874a3ad2ddSDean Nelson 				   (XPC_ENGAGED_PARTITIONS_AMO *
7884a3ad2ddSDean Nelson 				    sizeof(AMO_t)));
78945d9ca49SDean Nelson 
79045d9ca49SDean Nelson 	local_irq_save(irq_flags);
79145d9ca49SDean Nelson 
79245d9ca49SDean Nelson 	/* clear bit corresponding to our partid in remote partition's AMO */
79345d9ca49SDean Nelson 	FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_AND,
79445d9ca49SDean Nelson 			 ~(1UL << sn_partition_id));
79545d9ca49SDean Nelson 	/*
79645d9ca49SDean Nelson 	 * We must always use the nofault function regardless of whether we
79745d9ca49SDean Nelson 	 * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we
79845d9ca49SDean Nelson 	 * didn't, we'd never know that the other partition is down and would
79945d9ca49SDean Nelson 	 * keep sending IPIs and AMOs to it until the heartbeat times out.
80045d9ca49SDean Nelson 	 */
80145d9ca49SDean Nelson 	(void)xp_nofault_PIOR((u64 *)GLOBAL_MMR_ADDR(NASID_GET(&amo->
8024a3ad2ddSDean Nelson 							       variable),
8034a3ad2ddSDean Nelson 						     xp_nofault_PIOR_target));
80445d9ca49SDean Nelson 
80545d9ca49SDean Nelson 	local_irq_restore(irq_flags);
80645d9ca49SDean Nelson }
80745d9ca49SDean Nelson 
80845d9ca49SDean Nelson static inline void
80945d9ca49SDean Nelson xpc_request_partition_disengage(struct xpc_partition *part)
81045d9ca49SDean Nelson {
81145d9ca49SDean Nelson 	unsigned long irq_flags;
81245d9ca49SDean Nelson 	AMO_t *amo = (AMO_t *)__va(part->remote_amos_page_pa +
81345d9ca49SDean Nelson 				   (XPC_DISENGAGE_REQUEST_AMO * sizeof(AMO_t)));
81445d9ca49SDean Nelson 
81545d9ca49SDean Nelson 	local_irq_save(irq_flags);
81645d9ca49SDean Nelson 
81745d9ca49SDean Nelson 	/* set bit corresponding to our partid in remote partition's AMO */
81845d9ca49SDean Nelson 	FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_OR,
81945d9ca49SDean Nelson 			 (1UL << sn_partition_id));
82045d9ca49SDean Nelson 	/*
82145d9ca49SDean Nelson 	 * We must always use the nofault function regardless of whether we
82245d9ca49SDean Nelson 	 * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we
82345d9ca49SDean Nelson 	 * didn't, we'd never know that the other partition is down and would
82445d9ca49SDean Nelson 	 * keep sending IPIs and AMOs to it until the heartbeat times out.
82545d9ca49SDean Nelson 	 */
82645d9ca49SDean Nelson 	(void)xp_nofault_PIOR((u64 *)GLOBAL_MMR_ADDR(NASID_GET(&amo->
8274a3ad2ddSDean Nelson 							       variable),
8284a3ad2ddSDean Nelson 						     xp_nofault_PIOR_target));
82945d9ca49SDean Nelson 
83045d9ca49SDean Nelson 	local_irq_restore(irq_flags);
83145d9ca49SDean Nelson }
83245d9ca49SDean Nelson 
83345d9ca49SDean Nelson static inline void
83445d9ca49SDean Nelson xpc_cancel_partition_disengage_request(struct xpc_partition *part)
83545d9ca49SDean Nelson {
83645d9ca49SDean Nelson 	unsigned long irq_flags;
83745d9ca49SDean Nelson 	AMO_t *amo = (AMO_t *)__va(part->remote_amos_page_pa +
83845d9ca49SDean Nelson 				   (XPC_DISENGAGE_REQUEST_AMO * sizeof(AMO_t)));
83945d9ca49SDean Nelson 
84045d9ca49SDean Nelson 	local_irq_save(irq_flags);
84145d9ca49SDean Nelson 
84245d9ca49SDean Nelson 	/* clear bit corresponding to our partid in remote partition's AMO */
84345d9ca49SDean Nelson 	FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_AND,
84445d9ca49SDean Nelson 			 ~(1UL << sn_partition_id));
84545d9ca49SDean Nelson 	/*
84645d9ca49SDean Nelson 	 * We must always use the nofault function regardless of whether we
84745d9ca49SDean Nelson 	 * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we
84845d9ca49SDean Nelson 	 * didn't, we'd never know that the other partition is down and would
84945d9ca49SDean Nelson 	 * keep sending IPIs and AMOs to it until the heartbeat times out.
85045d9ca49SDean Nelson 	 */
85145d9ca49SDean Nelson 	(void)xp_nofault_PIOR((u64 *)GLOBAL_MMR_ADDR(NASID_GET(&amo->
8524a3ad2ddSDean Nelson 							       variable),
8534a3ad2ddSDean Nelson 						     xp_nofault_PIOR_target));
85445d9ca49SDean Nelson 
85545d9ca49SDean Nelson 	local_irq_restore(irq_flags);
85645d9ca49SDean Nelson }
85745d9ca49SDean Nelson 
85845d9ca49SDean Nelson static inline u64
85945d9ca49SDean Nelson xpc_partition_engaged(u64 partid_mask)
86045d9ca49SDean Nelson {
86145d9ca49SDean Nelson 	AMO_t *amo = xpc_vars->amos_page + XPC_ENGAGED_PARTITIONS_AMO;
86245d9ca49SDean Nelson 
86345d9ca49SDean Nelson 	/* return our partition's AMO variable ANDed with partid_mask */
86445d9ca49SDean Nelson 	return (FETCHOP_LOAD_OP(TO_AMO((u64)&amo->variable), FETCHOP_LOAD) &
86545d9ca49SDean Nelson 		partid_mask);
86645d9ca49SDean Nelson }
86745d9ca49SDean Nelson 
86845d9ca49SDean Nelson static inline u64
86945d9ca49SDean Nelson xpc_partition_disengage_requested(u64 partid_mask)
87045d9ca49SDean Nelson {
87145d9ca49SDean Nelson 	AMO_t *amo = xpc_vars->amos_page + XPC_DISENGAGE_REQUEST_AMO;
87245d9ca49SDean Nelson 
87345d9ca49SDean Nelson 	/* return our partition's AMO variable ANDed with partid_mask */
87445d9ca49SDean Nelson 	return (FETCHOP_LOAD_OP(TO_AMO((u64)&amo->variable), FETCHOP_LOAD) &
87545d9ca49SDean Nelson 		partid_mask);
87645d9ca49SDean Nelson }
87745d9ca49SDean Nelson 
87845d9ca49SDean Nelson static inline void
87945d9ca49SDean Nelson xpc_clear_partition_engaged(u64 partid_mask)
88045d9ca49SDean Nelson {
88145d9ca49SDean Nelson 	AMO_t *amo = xpc_vars->amos_page + XPC_ENGAGED_PARTITIONS_AMO;
88245d9ca49SDean Nelson 
88345d9ca49SDean Nelson 	/* clear bit(s) based on partid_mask in our partition's AMO */
88445d9ca49SDean Nelson 	FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_AND,
88545d9ca49SDean Nelson 			 ~partid_mask);
88645d9ca49SDean Nelson }
88745d9ca49SDean Nelson 
88845d9ca49SDean Nelson static inline void
88945d9ca49SDean Nelson xpc_clear_partition_disengage_request(u64 partid_mask)
89045d9ca49SDean Nelson {
89145d9ca49SDean Nelson 	AMO_t *amo = xpc_vars->amos_page + XPC_DISENGAGE_REQUEST_AMO;
89245d9ca49SDean Nelson 
89345d9ca49SDean Nelson 	/* clear bit(s) based on partid_mask in our partition's AMO */
89445d9ca49SDean Nelson 	FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_AND,
89545d9ca49SDean Nelson 			 ~partid_mask);
89645d9ca49SDean Nelson }
89745d9ca49SDean Nelson 
89845d9ca49SDean Nelson /*
89945d9ca49SDean Nelson  * The following set of macros and inlines are used for the sending and
90045d9ca49SDean Nelson  * receiving of IPIs (also known as IRQs). There are two flavors of IPIs,
90145d9ca49SDean Nelson  * one that is associated with partition activity (SGI_XPC_ACTIVATE) and
90245d9ca49SDean Nelson  * the other that is associated with channel activity (SGI_XPC_NOTIFY).
90345d9ca49SDean Nelson  */
90445d9ca49SDean Nelson 
90545d9ca49SDean Nelson static inline u64
90645d9ca49SDean Nelson xpc_IPI_receive(AMO_t *amo)
90745d9ca49SDean Nelson {
90845d9ca49SDean Nelson 	return FETCHOP_LOAD_OP(TO_AMO((u64)&amo->variable), FETCHOP_CLEAR);
90945d9ca49SDean Nelson }
91045d9ca49SDean Nelson 
91165c17b80SDean Nelson static inline enum xp_retval
91245d9ca49SDean Nelson xpc_IPI_send(AMO_t *amo, u64 flag, int nasid, int phys_cpuid, int vector)
91345d9ca49SDean Nelson {
91445d9ca49SDean Nelson 	int ret = 0;
91545d9ca49SDean Nelson 	unsigned long irq_flags;
91645d9ca49SDean Nelson 
91745d9ca49SDean Nelson 	local_irq_save(irq_flags);
91845d9ca49SDean Nelson 
91945d9ca49SDean Nelson 	FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_OR, flag);
92045d9ca49SDean Nelson 	sn_send_IPI_phys(nasid, phys_cpuid, vector, 0);
92145d9ca49SDean Nelson 
92245d9ca49SDean Nelson 	/*
92345d9ca49SDean Nelson 	 * We must always use the nofault function regardless of whether we
92445d9ca49SDean Nelson 	 * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we
92545d9ca49SDean Nelson 	 * didn't, we'd never know that the other partition is down and would
92645d9ca49SDean Nelson 	 * keep sending IPIs and AMOs to it until the heartbeat times out.
92745d9ca49SDean Nelson 	 */
92845d9ca49SDean Nelson 	ret = xp_nofault_PIOR((u64 *)GLOBAL_MMR_ADDR(NASID_GET(&amo->variable),
92945d9ca49SDean Nelson 						     xp_nofault_PIOR_target));
93045d9ca49SDean Nelson 
93145d9ca49SDean Nelson 	local_irq_restore(irq_flags);
93245d9ca49SDean Nelson 
93365c17b80SDean Nelson 	return ((ret == 0) ? xpSuccess : xpPioReadError);
93445d9ca49SDean Nelson }
93545d9ca49SDean Nelson 
93645d9ca49SDean Nelson /*
93745d9ca49SDean Nelson  * IPIs associated with SGI_XPC_ACTIVATE IRQ.
93845d9ca49SDean Nelson  */
93945d9ca49SDean Nelson 
94045d9ca49SDean Nelson /*
94145d9ca49SDean Nelson  * Flag the appropriate AMO variable and send an IPI to the specified node.
94245d9ca49SDean Nelson  */
94345d9ca49SDean Nelson static inline void
94445d9ca49SDean Nelson xpc_activate_IRQ_send(u64 amos_page_pa, int from_nasid, int to_nasid,
94545d9ca49SDean Nelson 		      int to_phys_cpuid)
94645d9ca49SDean Nelson {
94745d9ca49SDean Nelson 	int w_index = XPC_NASID_W_INDEX(from_nasid);
94845d9ca49SDean Nelson 	int b_index = XPC_NASID_B_INDEX(from_nasid);
94945d9ca49SDean Nelson 	AMO_t *amos = (AMO_t *)__va(amos_page_pa +
95045d9ca49SDean Nelson 				    (XPC_ACTIVATE_IRQ_AMOS * sizeof(AMO_t)));
95145d9ca49SDean Nelson 
95245d9ca49SDean Nelson 	(void)xpc_IPI_send(&amos[w_index], (1UL << b_index), to_nasid,
95345d9ca49SDean Nelson 			   to_phys_cpuid, SGI_XPC_ACTIVATE);
95445d9ca49SDean Nelson }
95545d9ca49SDean Nelson 
95645d9ca49SDean Nelson static inline void
95745d9ca49SDean Nelson xpc_IPI_send_activate(struct xpc_vars *vars)
95845d9ca49SDean Nelson {
95945d9ca49SDean Nelson 	xpc_activate_IRQ_send(vars->amos_page_pa, cnodeid_to_nasid(0),
96045d9ca49SDean Nelson 			      vars->act_nasid, vars->act_phys_cpuid);
96145d9ca49SDean Nelson }
96245d9ca49SDean Nelson 
96345d9ca49SDean Nelson static inline void
96445d9ca49SDean Nelson xpc_IPI_send_activated(struct xpc_partition *part)
96545d9ca49SDean Nelson {
96645d9ca49SDean Nelson 	xpc_activate_IRQ_send(part->remote_amos_page_pa, cnodeid_to_nasid(0),
9674a3ad2ddSDean Nelson 			      part->remote_act_nasid,
9684a3ad2ddSDean Nelson 			      part->remote_act_phys_cpuid);
96945d9ca49SDean Nelson }
97045d9ca49SDean Nelson 
97145d9ca49SDean Nelson static inline void
97245d9ca49SDean Nelson xpc_IPI_send_reactivate(struct xpc_partition *part)
97345d9ca49SDean Nelson {
97445d9ca49SDean Nelson 	xpc_activate_IRQ_send(xpc_vars->amos_page_pa, part->reactivate_nasid,
97545d9ca49SDean Nelson 			      xpc_vars->act_nasid, xpc_vars->act_phys_cpuid);
97645d9ca49SDean Nelson }
97745d9ca49SDean Nelson 
97845d9ca49SDean Nelson static inline void
97945d9ca49SDean Nelson xpc_IPI_send_disengage(struct xpc_partition *part)
98045d9ca49SDean Nelson {
98145d9ca49SDean Nelson 	xpc_activate_IRQ_send(part->remote_amos_page_pa, cnodeid_to_nasid(0),
9824a3ad2ddSDean Nelson 			      part->remote_act_nasid,
9834a3ad2ddSDean Nelson 			      part->remote_act_phys_cpuid);
98445d9ca49SDean Nelson }
98545d9ca49SDean Nelson 
98645d9ca49SDean Nelson /*
98745d9ca49SDean Nelson  * IPIs associated with SGI_XPC_NOTIFY IRQ.
98845d9ca49SDean Nelson  */
98945d9ca49SDean Nelson 
99045d9ca49SDean Nelson /*
99145d9ca49SDean Nelson  * Send an IPI to the remote partition that is associated with the
99245d9ca49SDean Nelson  * specified channel.
99345d9ca49SDean Nelson  */
99445d9ca49SDean Nelson #define XPC_NOTIFY_IRQ_SEND(_ch, _ipi_f, _irq_f) \
99545d9ca49SDean Nelson 		xpc_notify_IRQ_send(_ch, _ipi_f, #_ipi_f, _irq_f)
99645d9ca49SDean Nelson 
99745d9ca49SDean Nelson static inline void
99845d9ca49SDean Nelson xpc_notify_IRQ_send(struct xpc_channel *ch, u8 ipi_flag, char *ipi_flag_string,
99945d9ca49SDean Nelson 		    unsigned long *irq_flags)
100045d9ca49SDean Nelson {
100145d9ca49SDean Nelson 	struct xpc_partition *part = &xpc_partitions[ch->partid];
100265c17b80SDean Nelson 	enum xp_retval ret;
100345d9ca49SDean Nelson 
100445d9ca49SDean Nelson 	if (likely(part->act_state != XPC_P_DEACTIVATING)) {
100545d9ca49SDean Nelson 		ret = xpc_IPI_send(part->remote_IPI_amo_va,
100645d9ca49SDean Nelson 				   (u64)ipi_flag << (ch->number * 8),
100745d9ca49SDean Nelson 				   part->remote_IPI_nasid,
10084a3ad2ddSDean Nelson 				   part->remote_IPI_phys_cpuid, SGI_XPC_NOTIFY);
100945d9ca49SDean Nelson 		dev_dbg(xpc_chan, "%s sent to partid=%d, channel=%d, ret=%d\n",
101045d9ca49SDean Nelson 			ipi_flag_string, ch->partid, ch->number, ret);
101165c17b80SDean Nelson 		if (unlikely(ret != xpSuccess)) {
10122c2b94f9SDean Nelson 			if (irq_flags != NULL)
101345d9ca49SDean Nelson 				spin_unlock_irqrestore(&ch->lock, *irq_flags);
101445d9ca49SDean Nelson 			XPC_DEACTIVATE_PARTITION(part, ret);
10152c2b94f9SDean Nelson 			if (irq_flags != NULL)
101645d9ca49SDean Nelson 				spin_lock_irqsave(&ch->lock, *irq_flags);
101745d9ca49SDean Nelson 		}
101845d9ca49SDean Nelson 	}
101945d9ca49SDean Nelson }
102045d9ca49SDean Nelson 
102145d9ca49SDean Nelson /*
102245d9ca49SDean Nelson  * Make it look like the remote partition, which is associated with the
102345d9ca49SDean Nelson  * specified channel, sent us an IPI. This faked IPI will be handled
102445d9ca49SDean Nelson  * by xpc_dropped_IPI_check().
102545d9ca49SDean Nelson  */
102645d9ca49SDean Nelson #define XPC_NOTIFY_IRQ_SEND_LOCAL(_ch, _ipi_f) \
102745d9ca49SDean Nelson 		xpc_notify_IRQ_send_local(_ch, _ipi_f, #_ipi_f)
102845d9ca49SDean Nelson 
102945d9ca49SDean Nelson static inline void
103045d9ca49SDean Nelson xpc_notify_IRQ_send_local(struct xpc_channel *ch, u8 ipi_flag,
103145d9ca49SDean Nelson 			  char *ipi_flag_string)
103245d9ca49SDean Nelson {
103345d9ca49SDean Nelson 	struct xpc_partition *part = &xpc_partitions[ch->partid];
103445d9ca49SDean Nelson 
103545d9ca49SDean Nelson 	FETCHOP_STORE_OP(TO_AMO((u64)&part->local_IPI_amo_va->variable),
103645d9ca49SDean Nelson 			 FETCHOP_OR, ((u64)ipi_flag << (ch->number * 8)));
103745d9ca49SDean Nelson 	dev_dbg(xpc_chan, "%s sent local from partid=%d, channel=%d\n",
103845d9ca49SDean Nelson 		ipi_flag_string, ch->partid, ch->number);
103945d9ca49SDean Nelson }
104045d9ca49SDean Nelson 
104145d9ca49SDean Nelson /*
104245d9ca49SDean Nelson  * The sending and receiving of IPIs includes the setting of an AMO variable
104345d9ca49SDean Nelson  * to indicate the reason the IPI was sent. The 64-bit variable is divided
104445d9ca49SDean Nelson  * up into eight bytes, ordered from right to left. Byte zero pertains to
104545d9ca49SDean Nelson  * channel 0, byte one to channel 1, and so on. Each byte is described by
104645d9ca49SDean Nelson  * the following IPI flags.
104745d9ca49SDean Nelson  */
104845d9ca49SDean Nelson 
104945d9ca49SDean Nelson #define	XPC_IPI_CLOSEREQUEST	0x01
105045d9ca49SDean Nelson #define	XPC_IPI_CLOSEREPLY	0x02
105145d9ca49SDean Nelson #define	XPC_IPI_OPENREQUEST	0x04
105245d9ca49SDean Nelson #define	XPC_IPI_OPENREPLY	0x08
105345d9ca49SDean Nelson #define	XPC_IPI_MSGREQUEST	0x10
105445d9ca49SDean Nelson 
105545d9ca49SDean Nelson /* given an AMO variable and a channel#, get its associated IPI flags */
105645d9ca49SDean Nelson #define XPC_GET_IPI_FLAGS(_amo, _c)	((u8) (((_amo) >> ((_c) * 8)) & 0xff))
105745d9ca49SDean Nelson #define XPC_SET_IPI_FLAGS(_amo, _c, _f)	(_amo) |= ((u64) (_f) << ((_c) * 8))
105845d9ca49SDean Nelson 
10592c2b94f9SDean Nelson #define	XPC_ANY_OPENCLOSE_IPI_FLAGS_SET(_amo) ((_amo) & 0x0f0f0f0f0f0f0f0fUL)
10602c2b94f9SDean Nelson #define XPC_ANY_MSG_IPI_FLAGS_SET(_amo)       ((_amo) & 0x1010101010101010UL)
106145d9ca49SDean Nelson 
106245d9ca49SDean Nelson static inline void
106345d9ca49SDean Nelson xpc_IPI_send_closerequest(struct xpc_channel *ch, unsigned long *irq_flags)
106445d9ca49SDean Nelson {
106545d9ca49SDean Nelson 	struct xpc_openclose_args *args = ch->local_openclose_args;
106645d9ca49SDean Nelson 
106745d9ca49SDean Nelson 	args->reason = ch->reason;
106845d9ca49SDean Nelson 
106945d9ca49SDean Nelson 	XPC_NOTIFY_IRQ_SEND(ch, XPC_IPI_CLOSEREQUEST, irq_flags);
107045d9ca49SDean Nelson }
107145d9ca49SDean Nelson 
107245d9ca49SDean Nelson static inline void
107345d9ca49SDean Nelson xpc_IPI_send_closereply(struct xpc_channel *ch, unsigned long *irq_flags)
107445d9ca49SDean Nelson {
107545d9ca49SDean Nelson 	XPC_NOTIFY_IRQ_SEND(ch, XPC_IPI_CLOSEREPLY, irq_flags);
107645d9ca49SDean Nelson }
107745d9ca49SDean Nelson 
107845d9ca49SDean Nelson static inline void
107945d9ca49SDean Nelson xpc_IPI_send_openrequest(struct xpc_channel *ch, unsigned long *irq_flags)
108045d9ca49SDean Nelson {
108145d9ca49SDean Nelson 	struct xpc_openclose_args *args = ch->local_openclose_args;
108245d9ca49SDean Nelson 
108345d9ca49SDean Nelson 	args->msg_size = ch->msg_size;
108445d9ca49SDean Nelson 	args->local_nentries = ch->local_nentries;
108545d9ca49SDean Nelson 
108645d9ca49SDean Nelson 	XPC_NOTIFY_IRQ_SEND(ch, XPC_IPI_OPENREQUEST, irq_flags);
108745d9ca49SDean Nelson }
108845d9ca49SDean Nelson 
108945d9ca49SDean Nelson static inline void
109045d9ca49SDean Nelson xpc_IPI_send_openreply(struct xpc_channel *ch, unsigned long *irq_flags)
109145d9ca49SDean Nelson {
109245d9ca49SDean Nelson 	struct xpc_openclose_args *args = ch->local_openclose_args;
109345d9ca49SDean Nelson 
109445d9ca49SDean Nelson 	args->remote_nentries = ch->remote_nentries;
109545d9ca49SDean Nelson 	args->local_nentries = ch->local_nentries;
109645d9ca49SDean Nelson 	args->local_msgqueue_pa = __pa(ch->local_msgqueue);
109745d9ca49SDean Nelson 
109845d9ca49SDean Nelson 	XPC_NOTIFY_IRQ_SEND(ch, XPC_IPI_OPENREPLY, irq_flags);
109945d9ca49SDean Nelson }
110045d9ca49SDean Nelson 
110145d9ca49SDean Nelson static inline void
110245d9ca49SDean Nelson xpc_IPI_send_msgrequest(struct xpc_channel *ch)
110345d9ca49SDean Nelson {
110445d9ca49SDean Nelson 	XPC_NOTIFY_IRQ_SEND(ch, XPC_IPI_MSGREQUEST, NULL);
110545d9ca49SDean Nelson }
110645d9ca49SDean Nelson 
110745d9ca49SDean Nelson static inline void
110845d9ca49SDean Nelson xpc_IPI_send_local_msgrequest(struct xpc_channel *ch)
110945d9ca49SDean Nelson {
111045d9ca49SDean Nelson 	XPC_NOTIFY_IRQ_SEND_LOCAL(ch, XPC_IPI_MSGREQUEST);
111145d9ca49SDean Nelson }
111245d9ca49SDean Nelson 
111345d9ca49SDean Nelson /*
1114bc63d387SDean Nelson >>> this block comment needs to be moved and re-written.
111545d9ca49SDean Nelson  * Memory for XPC's AMO variables is allocated by the MSPEC driver. These
111645d9ca49SDean Nelson  * pages are located in the lowest granule. The lowest granule uses 4k pages
111745d9ca49SDean Nelson  * for cached references and an alternate TLB handler to never provide a
111845d9ca49SDean Nelson  * cacheable mapping for the entire region. This will prevent speculative
111945d9ca49SDean Nelson  * reading of cached copies of our lines from being issued which will cause
112045d9ca49SDean Nelson  * a PI FSB Protocol error to be generated by the SHUB. For XPC, we need 64
1121bc63d387SDean Nelson  * AMO variables (based on xp_max_npartitions) for message notification and an
112245d9ca49SDean Nelson  * additional 128 AMO variables (based on XP_NASID_MASK_WORDS) for partition
112345d9ca49SDean Nelson  * activation and 2 AMO variables for partition deactivation.
112445d9ca49SDean Nelson  */
112545d9ca49SDean Nelson static inline AMO_t *
112645d9ca49SDean Nelson xpc_IPI_init(int index)
112745d9ca49SDean Nelson {
112845d9ca49SDean Nelson 	AMO_t *amo = xpc_vars->amos_page + index;
112945d9ca49SDean Nelson 
113045d9ca49SDean Nelson 	(void)xpc_IPI_receive(amo);	/* clear AMO variable */
113145d9ca49SDean Nelson 	return amo;
113245d9ca49SDean Nelson }
113345d9ca49SDean Nelson 
113445d9ca49SDean Nelson /*
113545d9ca49SDean Nelson  * Check to see if there is any channel activity to/from the specified
113645d9ca49SDean Nelson  * partition.
113745d9ca49SDean Nelson  */
113845d9ca49SDean Nelson static inline void
113945d9ca49SDean Nelson xpc_check_for_channel_activity(struct xpc_partition *part)
114045d9ca49SDean Nelson {
114145d9ca49SDean Nelson 	u64 IPI_amo;
114245d9ca49SDean Nelson 	unsigned long irq_flags;
114345d9ca49SDean Nelson 
114445d9ca49SDean Nelson 	IPI_amo = xpc_IPI_receive(part->local_IPI_amo_va);
11452c2b94f9SDean Nelson 	if (IPI_amo == 0)
114645d9ca49SDean Nelson 		return;
114745d9ca49SDean Nelson 
114845d9ca49SDean Nelson 	spin_lock_irqsave(&part->IPI_lock, irq_flags);
114945d9ca49SDean Nelson 	part->local_IPI_amo |= IPI_amo;
115045d9ca49SDean Nelson 	spin_unlock_irqrestore(&part->IPI_lock, irq_flags);
115145d9ca49SDean Nelson 
115245d9ca49SDean Nelson 	dev_dbg(xpc_chan, "received IPI from partid=%d, IPI_amo=0x%lx\n",
115345d9ca49SDean Nelson 		XPC_PARTID(part), IPI_amo);
115445d9ca49SDean Nelson 
115545d9ca49SDean Nelson 	xpc_wakeup_channel_mgr(part);
115645d9ca49SDean Nelson }
115745d9ca49SDean Nelson 
115845d9ca49SDean Nelson #endif /* _DRIVERS_MISC_SGIXP_XPC_H */
1159