xpc_main.c revision 45d9ca492e4bd1522d1b5bd125c2908f1cee3d4a
189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson/*
289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * This file is subject to the terms and conditions of the GNU General Public
389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * License.  See the file "COPYING" in the main directory of this archive
489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * for more details.
589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *
645d9ca492e4bd1522d1b5bd125c2908f1cee3d4aDean Nelson * Copyright (c) 2004-2008 Silicon Graphics, Inc.  All Rights Reserved.
789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson */
889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
1089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson/*
1189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * Cross Partition Communication (XPC) support - standard version.
1289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *
1389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *	XPC provides a message passing capability that crosses partition
1489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *	boundaries. This module is made up of two parts:
1589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *
1689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *	    partition	This part detects the presence/absence of other
1789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *			partitions. It provides a heartbeat and monitors
1889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *			the heartbeats of other partitions.
1989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *
2089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *	    channel	This part manages the channels and sends/receives
2189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *			messages across them to/from other partitions.
2289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *
2389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *	There are a couple of additional functions residing in XP, which
2489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *	provide an interface to XPC for its users.
2589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *
2689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *
2789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *	Caveats:
2889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *
2989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *	  . We currently have no way to determine which nasid an IPI came
3089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *	    from. Thus, xpc_IPI_send() does a remote AMO write followed by
3189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *	    an IPI. The AMO indicates where data is to be pulled from, so
3289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *	    after the IPI arrives, the remote partition checks the AMO word.
3389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *	    The IPI can actually arrive before the AMO however, so other code
3489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *	    must periodically check for this case. Also, remote AMO operations
3589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *	    do not reliably time out. Thus we do a remote PIO read solely to
3689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *	    know whether the remote partition is down and whether we should
3789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *	    stop sending IPIs to it. This remote PIO read operation is set up
3889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *	    in a special nofault region so SAL knows to ignore (and cleanup)
3989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *	    any errors due to the remote AMO write, PIO read, and/or PIO
4089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *	    write operations.
4189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *
4289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *	    If/when new hardware solves this IPI problem, we should abandon
4389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *	    the current approach.
4489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *
4589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson */
4689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
4789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
4889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson#include <linux/kernel.h>
4989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson#include <linux/module.h>
5089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson#include <linux/init.h>
5189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson#include <linux/sched.h>
5289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson#include <linux/syscalls.h>
5389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson#include <linux/cache.h>
5489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson#include <linux/interrupt.h>
55699139279d29e36e39d353b0536b510dab2e5ffaNishanth Aravamudan#include <linux/delay.h>
56a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson#include <linux/reboot.h>
57f9e505a9a03df5acace6e758c8d12982635a1c64Jes Sorensen#include <linux/completion.h>
581eeb66a1bb973534dc3d064920a5ca683823372eChristoph Hellwig#include <linux/kdebug.h>
5989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson#include <asm/sn/intr.h>
6089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson#include <asm/sn/sn_sal.h>
6189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson#include <asm/uaccess.h>
6245d9ca492e4bd1522d1b5bd125c2908f1cee3d4aDean Nelson#include "xpc.h"
6389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
6489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
6589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson/* define two XPC debug device structures to be used with dev_dbg() et al */
6689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
6789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonstruct device_driver xpc_dbg_name = {
6889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	.name = "xpc"
6989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson};
7089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
7189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonstruct device xpc_part_dbg_subname = {
7289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	.bus_id = {0},		/* set to "part" at xpc_init() time */
7389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	.driver = &xpc_dbg_name
7489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson};
7589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
7689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonstruct device xpc_chan_dbg_subname = {
7789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	.bus_id = {0},		/* set to "chan" at xpc_init() time */
7889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	.driver = &xpc_dbg_name
7989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson};
8089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
8189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonstruct device *xpc_part = &xpc_part_dbg_subname;
8289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonstruct device *xpc_chan = &xpc_chan_dbg_subname;
8389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
8489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
851f4674b2d5f63bac4c393ac4de1d6c1b6b72c09cDean Nelsonstatic int xpc_kdebug_ignore;
861f4674b2d5f63bac4c393ac4de1d6c1b6b72c09cDean Nelson
871f4674b2d5f63bac4c393ac4de1d6c1b6b72c09cDean Nelson
8889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson/* systune related variables for /proc/sys directories */
8989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
90a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelsonstatic int xpc_hb_interval = XPC_HB_DEFAULT_INTERVAL;
91a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelsonstatic int xpc_hb_min_interval = 1;
92a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelsonstatic int xpc_hb_max_interval = 10;
9389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
94a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelsonstatic int xpc_hb_check_interval = XPC_HB_CHECK_DEFAULT_INTERVAL;
95a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelsonstatic int xpc_hb_check_min_interval = 10;
96a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelsonstatic int xpc_hb_check_max_interval = 120;
9789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
98e54af724c1ae3530c95135157776c9be65cdb747Dean Nelsonint xpc_disengage_request_timelimit = XPC_DISENGAGE_REQUEST_DEFAULT_TIMELIMIT;
99e54af724c1ae3530c95135157776c9be65cdb747Dean Nelsonstatic int xpc_disengage_request_min_timelimit = 0;
100e54af724c1ae3530c95135157776c9be65cdb747Dean Nelsonstatic int xpc_disengage_request_max_timelimit = 120;
10189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
10289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonstatic ctl_table xpc_sys_xpc_hb_dir[] = {
10389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	{
10468cbf0753681b3f79437f16d2f9a259b9346cf84Eric W. Biederman		.ctl_name 	= CTL_UNNUMBERED,
10568cbf0753681b3f79437f16d2f9a259b9346cf84Eric W. Biederman		.procname	= "hb_interval",
10668cbf0753681b3f79437f16d2f9a259b9346cf84Eric W. Biederman		.data		= &xpc_hb_interval,
10768cbf0753681b3f79437f16d2f9a259b9346cf84Eric W. Biederman		.maxlen		= sizeof(int),
10868cbf0753681b3f79437f16d2f9a259b9346cf84Eric W. Biederman		.mode		= 0644,
10968cbf0753681b3f79437f16d2f9a259b9346cf84Eric W. Biederman		.proc_handler	= &proc_dointvec_minmax,
11068cbf0753681b3f79437f16d2f9a259b9346cf84Eric W. Biederman		.strategy	= &sysctl_intvec,
11168cbf0753681b3f79437f16d2f9a259b9346cf84Eric W. Biederman		.extra1		= &xpc_hb_min_interval,
11268cbf0753681b3f79437f16d2f9a259b9346cf84Eric W. Biederman		.extra2		= &xpc_hb_max_interval
11389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	},
11489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	{
11568cbf0753681b3f79437f16d2f9a259b9346cf84Eric W. Biederman		.ctl_name	= CTL_UNNUMBERED,
11668cbf0753681b3f79437f16d2f9a259b9346cf84Eric W. Biederman		.procname	= "hb_check_interval",
11768cbf0753681b3f79437f16d2f9a259b9346cf84Eric W. Biederman		.data		= &xpc_hb_check_interval,
11868cbf0753681b3f79437f16d2f9a259b9346cf84Eric W. Biederman		.maxlen		= sizeof(int),
11968cbf0753681b3f79437f16d2f9a259b9346cf84Eric W. Biederman		.mode		= 0644,
12068cbf0753681b3f79437f16d2f9a259b9346cf84Eric W. Biederman		.proc_handler	= &proc_dointvec_minmax,
12168cbf0753681b3f79437f16d2f9a259b9346cf84Eric W. Biederman		.strategy	= &sysctl_intvec,
12268cbf0753681b3f79437f16d2f9a259b9346cf84Eric W. Biederman		.extra1		= &xpc_hb_check_min_interval,
12368cbf0753681b3f79437f16d2f9a259b9346cf84Eric W. Biederman		.extra2		= &xpc_hb_check_max_interval
12489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	},
12568cbf0753681b3f79437f16d2f9a259b9346cf84Eric W. Biederman	{}
12689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson};
12789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonstatic ctl_table xpc_sys_xpc_dir[] = {
12889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	{
12968cbf0753681b3f79437f16d2f9a259b9346cf84Eric W. Biederman		.ctl_name	= CTL_UNNUMBERED,
13068cbf0753681b3f79437f16d2f9a259b9346cf84Eric W. Biederman		.procname	= "hb",
13168cbf0753681b3f79437f16d2f9a259b9346cf84Eric W. Biederman		.mode		= 0555,
13268cbf0753681b3f79437f16d2f9a259b9346cf84Eric W. Biederman		.child		= xpc_sys_xpc_hb_dir
13389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	},
134e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson	{
13568cbf0753681b3f79437f16d2f9a259b9346cf84Eric W. Biederman		.ctl_name	= CTL_UNNUMBERED,
13668cbf0753681b3f79437f16d2f9a259b9346cf84Eric W. Biederman		.procname	= "disengage_request_timelimit",
13768cbf0753681b3f79437f16d2f9a259b9346cf84Eric W. Biederman		.data		= &xpc_disengage_request_timelimit,
13868cbf0753681b3f79437f16d2f9a259b9346cf84Eric W. Biederman		.maxlen		= sizeof(int),
13968cbf0753681b3f79437f16d2f9a259b9346cf84Eric W. Biederman		.mode		= 0644,
14068cbf0753681b3f79437f16d2f9a259b9346cf84Eric W. Biederman		.proc_handler	= &proc_dointvec_minmax,
14168cbf0753681b3f79437f16d2f9a259b9346cf84Eric W. Biederman		.strategy	= &sysctl_intvec,
14268cbf0753681b3f79437f16d2f9a259b9346cf84Eric W. Biederman		.extra1		= &xpc_disengage_request_min_timelimit,
14368cbf0753681b3f79437f16d2f9a259b9346cf84Eric W. Biederman		.extra2		= &xpc_disengage_request_max_timelimit
144e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson	},
14568cbf0753681b3f79437f16d2f9a259b9346cf84Eric W. Biederman	{}
14689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson};
14789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonstatic ctl_table xpc_sys_dir[] = {
14889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	{
14968cbf0753681b3f79437f16d2f9a259b9346cf84Eric W. Biederman		.ctl_name	= CTL_UNNUMBERED,
15068cbf0753681b3f79437f16d2f9a259b9346cf84Eric W. Biederman		.procname	= "xpc",
15168cbf0753681b3f79437f16d2f9a259b9346cf84Eric W. Biederman		.mode		= 0555,
15268cbf0753681b3f79437f16d2f9a259b9346cf84Eric W. Biederman		.child		= xpc_sys_xpc_dir
15389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	},
15468cbf0753681b3f79437f16d2f9a259b9346cf84Eric W. Biederman	{}
15589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson};
15689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonstatic struct ctl_table_header *xpc_sysctl;
15789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
1581ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson/* non-zero if any remote partition disengage request was timed out */
1591ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelsonint xpc_disengage_request_timedout;
16089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
16189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson/* #of IRQs received */
16289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonstatic atomic_t xpc_act_IRQ_rcvd;
16389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
16489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson/* IRQ handler notifies this wait queue on receipt of an IRQ */
16589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonstatic DECLARE_WAIT_QUEUE_HEAD(xpc_act_IRQ_wq);
16689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
16789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonstatic unsigned long xpc_hb_check_timeout;
16889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
169e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson/* notification that the xpc_hb_checker thread has exited */
170f9e505a9a03df5acace6e758c8d12982635a1c64Jes Sorensenstatic DECLARE_COMPLETION(xpc_hb_checker_exited);
17189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
172e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson/* notification that the xpc_discovery thread has exited */
173f9e505a9a03df5acace6e758c8d12982635a1c64Jes Sorensenstatic DECLARE_COMPLETION(xpc_discovery_exited);
17489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
17589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
17689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonstatic struct timer_list xpc_hb_timer;
17789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
17889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
17989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonstatic void xpc_kthread_waitmsgs(struct xpc_partition *, struct xpc_channel *);
18089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
18189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
182a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelsonstatic int xpc_system_reboot(struct notifier_block *, unsigned long, void *);
183a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelsonstatic struct notifier_block xpc_reboot_notifier = {
184a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson	.notifier_call = xpc_system_reboot,
185a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson};
186a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson
187780d09e895032207a6b070a44d392a3c60574b70Dean Nelsonstatic int xpc_system_die(struct notifier_block *, unsigned long, void *);
188780d09e895032207a6b070a44d392a3c60574b70Dean Nelsonstatic struct notifier_block xpc_die_notifier = {
189780d09e895032207a6b070a44d392a3c60574b70Dean Nelson	.notifier_call = xpc_system_die,
190780d09e895032207a6b070a44d392a3c60574b70Dean Nelson};
191780d09e895032207a6b070a44d392a3c60574b70Dean Nelson
192a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson
193a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson/*
194a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson * Timer function to enforce the timelimit on the partition disengage request.
195a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson */
196a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelsonstatic void
197a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelsonxpc_timeout_partition_disengage_request(unsigned long data)
198a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson{
199a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson	struct xpc_partition *part = (struct xpc_partition *) data;
200a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson
201a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson
202d167cb85150bd473a27df71e3116a9cc0008f5ddRobert P. J. Day	DBUG_ON(time_before(jiffies, part->disengage_request_timeout));
203a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson
204a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson	(void) xpc_partition_disengaged(part);
205a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson
206a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson	DBUG_ON(part->disengage_request_timeout != 0);
207a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson	DBUG_ON(xpc_partition_engaged(1UL << XPC_PARTID(part)) != 0);
208a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson}
209a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson
210a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson
21189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson/*
21289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * Notify the heartbeat check thread that an IRQ has been received.
21389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson */
21489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonstatic irqreturn_t
2155dcded1b0b4f1537bb6dff453fb805517756c94bAl Viroxpc_act_IRQ_handler(int irq, void *dev_id)
21689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson{
21789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	atomic_inc(&xpc_act_IRQ_rcvd);
21889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	wake_up_interruptible(&xpc_act_IRQ_wq);
21989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	return IRQ_HANDLED;
22089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson}
22189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
22289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
22389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson/*
22489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * Timer to produce the heartbeat.  The timer structures function is
22589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * already set when this is initially called.  A tunable is used to
22689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * specify when the next timeout should occur.
22789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson */
22889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonstatic void
22989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonxpc_hb_beater(unsigned long dummy)
23089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson{
23189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	xpc_vars->heartbeat++;
23289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
233d167cb85150bd473a27df71e3116a9cc0008f5ddRobert P. J. Day	if (time_after_eq(jiffies, xpc_hb_check_timeout)) {
23489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		wake_up_interruptible(&xpc_act_IRQ_wq);
23589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	}
23689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
23789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	xpc_hb_timer.expires = jiffies + (xpc_hb_interval * HZ);
23889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	add_timer(&xpc_hb_timer);
23989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson}
24089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
24189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
24289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson/*
24389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * This thread is responsible for nearly all of the partition
24489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * activation/deactivation.
24589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson */
24689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonstatic int
24789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonxpc_hb_checker(void *ignore)
24889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson{
24989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	int last_IRQ_count = 0;
25089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	int new_IRQ_count;
25189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	int force_IRQ=0;
25289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
25389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
25489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	/* this thread was marked active by xpc_hb_init() */
25589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
25689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	daemonize(XPC_HB_CHECK_THREAD_NAME);
25789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
25889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	set_cpus_allowed(current, cpumask_of_cpu(XPC_HB_CHECK_CPU));
25989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
2604c013f5c7ea39cd62e02c80408560751b4e8c0deDean Nelson	/* set our heartbeating to other partitions into motion */
26189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	xpc_hb_check_timeout = jiffies + (xpc_hb_check_interval * HZ);
2624c013f5c7ea39cd62e02c80408560751b4e8c0deDean Nelson	xpc_hb_beater(0);
26389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
26489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	while (!(volatile int) xpc_exiting) {
26589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
26689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		dev_dbg(xpc_part, "woke up with %d ticks rem; %d IRQs have "
26789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			"been received\n",
26889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			(int) (xpc_hb_check_timeout - jiffies),
26989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			atomic_read(&xpc_act_IRQ_rcvd) - last_IRQ_count);
27089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
27189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
27289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		/* checking of remote heartbeats is skewed by IRQ handling */
273d167cb85150bd473a27df71e3116a9cc0008f5ddRobert P. J. Day		if (time_after_eq(jiffies, xpc_hb_check_timeout)) {
27489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			dev_dbg(xpc_part, "checking remote heartbeats\n");
27589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			xpc_check_remote_hb();
27689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
27789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			/*
27889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			 * We need to periodically recheck to ensure no
27989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			 * IPI/AMO pairs have been missed.  That check
28089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			 * must always reset xpc_hb_check_timeout.
28189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			 */
28289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			force_IRQ = 1;
28389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		}
28489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
28589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
286a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson		/* check for outstanding IRQs */
28789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		new_IRQ_count = atomic_read(&xpc_act_IRQ_rcvd);
28889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		if (last_IRQ_count < new_IRQ_count || force_IRQ != 0) {
28989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			force_IRQ = 0;
29089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
29189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			dev_dbg(xpc_part, "found an IRQ to process; will be "
29289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson				"resetting xpc_hb_check_timeout\n");
29389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
29489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			last_IRQ_count += xpc_identify_act_IRQ_sender();
29589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			if (last_IRQ_count < new_IRQ_count) {
29689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson				/* retry once to help avoid missing AMO */
29789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson				(void) xpc_identify_act_IRQ_sender();
29889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			}
29989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			last_IRQ_count = new_IRQ_count;
30089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
30189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			xpc_hb_check_timeout = jiffies +
30289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson					   (xpc_hb_check_interval * HZ);
30389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		}
304a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson
305a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson		/* wait for IRQ or timeout */
306a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson		(void) wait_event_interruptible(xpc_act_IRQ_wq,
307a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson			    (last_IRQ_count < atomic_read(&xpc_act_IRQ_rcvd) ||
308d167cb85150bd473a27df71e3116a9cc0008f5ddRobert P. J. Day					time_after_eq(jiffies, xpc_hb_check_timeout) ||
309a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson						(volatile int) xpc_exiting));
31089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	}
31189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
31289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	dev_dbg(xpc_part, "heartbeat checker is exiting\n");
31389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
31489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
315e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson	/* mark this thread as having exited */
316f9e505a9a03df5acace6e758c8d12982635a1c64Jes Sorensen	complete(&xpc_hb_checker_exited);
31789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	return 0;
31889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson}
31989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
32089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
32189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson/*
32289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * This thread will attempt to discover other partitions to activate
32389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * based on info provided by SAL. This new thread is short lived and
32489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * will exit once discovery is complete.
32589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson */
32689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonstatic int
32789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonxpc_initiate_discovery(void *ignore)
32889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson{
32989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	daemonize(XPC_DISCOVERY_THREAD_NAME);
33089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
33189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	xpc_discovery();
33289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
33389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	dev_dbg(xpc_part, "discovery thread is exiting\n");
33489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
335e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson	/* mark this thread as having exited */
336f9e505a9a03df5acace6e758c8d12982635a1c64Jes Sorensen	complete(&xpc_discovery_exited);
33789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	return 0;
33889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson}
33989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
34089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
34189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson/*
34289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * Establish first contact with the remote partititon. This involves pulling
34389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * the XPC per partition variables from the remote partition and waiting for
34489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * the remote partition to pull ours.
34589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson */
34689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonstatic enum xpc_retval
34789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonxpc_make_first_contact(struct xpc_partition *part)
34889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson{
34989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	enum xpc_retval ret;
35089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
35189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
35289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	while ((ret = xpc_pull_remote_vars_part(part)) != xpcSuccess) {
35389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		if (ret != xpcRetry) {
35489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			XPC_DEACTIVATE_PARTITION(part, ret);
35589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			return ret;
35689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		}
35789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
35889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		dev_dbg(xpc_chan, "waiting to make first contact with "
35989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			"partition %d\n", XPC_PARTID(part));
36089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
36189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		/* wait a 1/4 of a second or so */
362a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson		(void) msleep_interruptible(250);
36389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
36489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		if (part->act_state == XPC_P_DEACTIVATING) {
36589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			return part->reason;
36689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		}
36789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	}
36889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
36989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	return xpc_mark_partition_active(part);
37089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson}
37189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
37289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
37389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson/*
37489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * The first kthread assigned to a newly activated partition is the one
37589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * created by XPC HB with which it calls xpc_partition_up(). XPC hangs on to
37689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * that kthread until the partition is brought down, at which time that kthread
37789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * returns back to XPC HB. (The return of that kthread will signify to XPC HB
37889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * that XPC has dismantled all communication infrastructure for the associated
37989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * partition.) This kthread becomes the channel manager for that partition.
38089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *
38189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * Each active partition has a channel manager, who, besides connecting and
38289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * disconnecting channels, will ensure that each of the partition's connected
38389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * channels has the required number of assigned kthreads to get the work done.
38489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson */
38589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonstatic void
38689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonxpc_channel_mgr(struct xpc_partition *part)
38789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson{
38889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	while (part->act_state != XPC_P_DEACTIVATING ||
389a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson			atomic_read(&part->nchannels_active) > 0 ||
390a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson					!xpc_partition_disengaged(part)) {
39189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
39289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		xpc_process_channel_activity(part);
39389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
39489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
39589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		/*
39689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		 * Wait until we've been requested to activate kthreads or
39789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		 * all of the channel's message queues have been torn down or
39889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		 * a signal is pending.
39989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		 *
40089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		 * The channel_mgr_requests is set to 1 after being awakened,
40189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		 * This is done to prevent the channel mgr from making one pass
40289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		 * through the loop for each request, since he will
40389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		 * be servicing all the requests in one pass. The reason it's
40489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		 * set to 1 instead of 0 is so that other kthreads will know
40589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		 * that the channel mgr is running and won't bother trying to
40689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		 * wake him up.
40789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		 */
40889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		atomic_dec(&part->channel_mgr_requests);
40989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		(void) wait_event_interruptible(part->channel_mgr_wq,
41089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson				(atomic_read(&part->channel_mgr_requests) > 0 ||
41189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson				(volatile u64) part->local_IPI_amo != 0 ||
41289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson				((volatile u8) part->act_state ==
41389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson							XPC_P_DEACTIVATING &&
414a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson				atomic_read(&part->nchannels_active) == 0 &&
415a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson				xpc_partition_disengaged(part))));
41689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		atomic_set(&part->channel_mgr_requests, 1);
41789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
41889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		// >>> Does it need to wakeup periodically as well? In case we
41989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		// >>> miscalculated the #of kthreads to wakeup or create?
42089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	}
42189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson}
42289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
42389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
42489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson/*
42589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * When XPC HB determines that a partition has come up, it will create a new
42689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * kthread and that kthread will call this function to attempt to set up the
42789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * basic infrastructure used for Cross Partition Communication with the newly
42889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * upped partition.
42989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *
43089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * The kthread that was created by XPC HB and which setup the XPC
43189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * infrastructure will remain assigned to the partition until the partition
43289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * goes down. At which time the kthread will teardown the XPC infrastructure
43389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * and then exit.
43489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *
43589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * XPC HB will put the remote partition's XPC per partition specific variables
43689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * physical address into xpc_partitions[partid].remote_vars_part_pa prior to
43789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * calling xpc_partition_up().
43889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson */
43989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonstatic void
44089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonxpc_partition_up(struct xpc_partition *part)
44189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson{
44289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	DBUG_ON(part->channels != NULL);
44389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
44489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	dev_dbg(xpc_chan, "activating partition %d\n", XPC_PARTID(part));
44589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
44689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	if (xpc_setup_infrastructure(part) != xpcSuccess) {
44789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		return;
44889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	}
44989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
45089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	/*
45189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 * The kthread that XPC HB called us with will become the
45289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 * channel manager for this partition. It will not return
45389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 * back to XPC HB until the partition's XPC infrastructure
45489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 * has been dismantled.
45589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 */
45689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
45789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	(void) xpc_part_ref(part);	/* this will always succeed */
45889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
45989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	if (xpc_make_first_contact(part) == xpcSuccess) {
46089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		xpc_channel_mgr(part);
46189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	}
46289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
46389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	xpc_part_deref(part);
46489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
46589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	xpc_teardown_infrastructure(part);
46689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson}
46789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
46889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
46989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonstatic int
47089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonxpc_activating(void *__partid)
47189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson{
47289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	partid_t partid = (u64) __partid;
47389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	struct xpc_partition *part = &xpc_partitions[partid];
47489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	unsigned long irq_flags;
475e037cda559547e6353c5a792802963572d0b750eKeith Owens	struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 };
47689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	int ret;
47789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
47889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
47989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	DBUG_ON(partid <= 0 || partid >= XP_MAX_PARTITIONS);
48089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
48189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	spin_lock_irqsave(&part->act_lock, irq_flags);
48289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
48389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	if (part->act_state == XPC_P_DEACTIVATING) {
48489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		part->act_state = XPC_P_INACTIVE;
48589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		spin_unlock_irqrestore(&part->act_lock, irq_flags);
48689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		part->remote_rp_pa = 0;
48789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		return 0;
48889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	}
48989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
49089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	/* indicate the thread is activating */
49189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	DBUG_ON(part->act_state != XPC_P_ACTIVATION_REQ);
49289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	part->act_state = XPC_P_ACTIVATING;
49389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
49489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	XPC_SET_REASON(part, 0, 0);
49589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	spin_unlock_irqrestore(&part->act_lock, irq_flags);
49689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
49789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	dev_dbg(xpc_part, "bringing partition %d up\n", partid);
49889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
49989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	daemonize("xpc%02d", partid);
50089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
50189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	/*
50289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 * This thread needs to run at a realtime priority to prevent a
50389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 * significant performance degradation.
50489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 */
50589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	ret = sched_setscheduler(current, SCHED_FIFO, &param);
50689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	if (ret != 0) {
50789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		dev_warn(xpc_part, "unable to set pid %d to a realtime "
50889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			"priority, ret=%d\n", current->pid, ret);
50989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	}
51089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
51189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	/* allow this thread and its children to run on any CPU */
51289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	set_cpus_allowed(current, CPU_MASK_ALL);
51389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
51489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	/*
51589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 * Register the remote partition's AMOs with SAL so it can handle
51689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 * and cleanup errors within that address range should the remote
51789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 * partition go down. We don't unregister this range because it is
51889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 * difficult to tell when outstanding writes to the remote partition
51989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 * are finished and thus when it is safe to unregister. This should
52089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 * not result in wasted space in the SAL xp_addr_region table because
52189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 * we should get the same page for remote_amos_page_pa after module
52289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 * reloads and system reboots.
52389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 */
52489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	if (sn_register_xp_addr_region(part->remote_amos_page_pa,
52589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson							PAGE_SIZE, 1) < 0) {
52689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		dev_warn(xpc_part, "xpc_partition_up(%d) failed to register "
52789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			"xp_addr region\n", partid);
52889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
52989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		spin_lock_irqsave(&part->act_lock, irq_flags);
53089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		part->act_state = XPC_P_INACTIVE;
53189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		XPC_SET_REASON(part, xpcPhysAddrRegFailed, __LINE__);
53289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		spin_unlock_irqrestore(&part->act_lock, irq_flags);
53389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		part->remote_rp_pa = 0;
53489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		return 0;
53589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	}
53689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
537a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson	xpc_allow_hb(partid, xpc_vars);
53889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	xpc_IPI_send_activated(part);
53989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
54089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
54189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	/*
54289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 * xpc_partition_up() holds this thread and marks this partition as
54389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 * XPC_P_ACTIVE by calling xpc_hb_mark_active().
54489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 */
54589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	(void) xpc_partition_up(part);
54689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
547a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson	xpc_disallow_hb(partid, xpc_vars);
54889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	xpc_mark_partition_inactive(part);
54989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
55089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	if (part->reason == xpcReactivating) {
55189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		/* interrupting ourselves results in activating partition */
55289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		xpc_IPI_send_reactivate(part);
55389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	}
55489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
55589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	return 0;
55689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson}
55789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
55889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
55989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonvoid
56089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonxpc_activate_partition(struct xpc_partition *part)
56189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson{
56289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	partid_t partid = XPC_PARTID(part);
56389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	unsigned long irq_flags;
56489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	pid_t pid;
56589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
56689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
56789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	spin_lock_irqsave(&part->act_lock, irq_flags);
56889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
56989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	DBUG_ON(part->act_state != XPC_P_INACTIVE);
57089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
5717c6c66362941df847957766ad133ff5fde67579cRobin Holt	part->act_state = XPC_P_ACTIVATION_REQ;
5727c6c66362941df847957766ad133ff5fde67579cRobin Holt	XPC_SET_REASON(part, xpcCloneKThread, __LINE__);
57389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
57489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	spin_unlock_irqrestore(&part->act_lock, irq_flags);
5757c6c66362941df847957766ad133ff5fde67579cRobin Holt
5767c6c66362941df847957766ad133ff5fde67579cRobin Holt	pid = kernel_thread(xpc_activating, (void *) ((u64) partid), 0);
5777c6c66362941df847957766ad133ff5fde67579cRobin Holt
5787c6c66362941df847957766ad133ff5fde67579cRobin Holt	if (unlikely(pid <= 0)) {
5797c6c66362941df847957766ad133ff5fde67579cRobin Holt		spin_lock_irqsave(&part->act_lock, irq_flags);
5807c6c66362941df847957766ad133ff5fde67579cRobin Holt		part->act_state = XPC_P_INACTIVE;
5817c6c66362941df847957766ad133ff5fde67579cRobin Holt		XPC_SET_REASON(part, xpcCloneKThreadFailed, __LINE__);
5827c6c66362941df847957766ad133ff5fde67579cRobin Holt		spin_unlock_irqrestore(&part->act_lock, irq_flags);
5837c6c66362941df847957766ad133ff5fde67579cRobin Holt	}
58489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson}
58589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
58689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
58789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson/*
58889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * Handle the receipt of a SGI_XPC_NOTIFY IRQ by seeing whether the specified
58989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * partition actually sent it. Since SGI_XPC_NOTIFY IRQs may be shared by more
59089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * than one partition, we use an AMO_t structure per partition to indicate
59189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * whether a partition has sent an IPI or not.  >>> If it has, then wake up the
59289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * associated kthread to handle it.
59389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *
59489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * All SGI_XPC_NOTIFY IRQs received by XPC are the result of IPIs sent by XPC
59589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * running on other partitions.
59689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *
59789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * Noteworthy Arguments:
59889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *
59989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *	irq - Interrupt ReQuest number. NOT USED.
60089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *
60189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *	dev_id - partid of IPI's potential sender.
60289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson */
60389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonirqreturn_t
6045dcded1b0b4f1537bb6dff453fb805517756c94bAl Viroxpc_notify_IRQ_handler(int irq, void *dev_id)
60589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson{
60689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	partid_t partid = (partid_t) (u64) dev_id;
60789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	struct xpc_partition *part = &xpc_partitions[partid];
60889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
60989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
61089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	DBUG_ON(partid <= 0 || partid >= XP_MAX_PARTITIONS);
61189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
61289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	if (xpc_part_ref(part)) {
61389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		xpc_check_for_channel_activity(part);
61489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
61589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		xpc_part_deref(part);
61689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	}
61789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	return IRQ_HANDLED;
61889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson}
61989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
62089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
62189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson/*
62289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * Check to see if xpc_notify_IRQ_handler() dropped any IPIs on the floor
62389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * because the write to their associated IPI amo completed after the IRQ/IPI
62489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * was received.
62589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson */
62689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonvoid
62789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonxpc_dropped_IPI_check(struct xpc_partition *part)
62889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson{
62989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	if (xpc_part_ref(part)) {
63089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		xpc_check_for_channel_activity(part);
63189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
63289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		part->dropped_IPI_timer.expires = jiffies +
63389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson							XPC_P_DROPPED_IPI_WAIT;
63489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		add_timer(&part->dropped_IPI_timer);
63589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		xpc_part_deref(part);
63689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	}
63789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson}
63889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
63989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
64089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonvoid
64189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonxpc_activate_kthreads(struct xpc_channel *ch, int needed)
64289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson{
64389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	int idle = atomic_read(&ch->kthreads_idle);
64489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	int assigned = atomic_read(&ch->kthreads_assigned);
64589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	int wakeup;
64689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
64789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
64889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	DBUG_ON(needed <= 0);
64989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
65089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	if (idle > 0) {
65189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		wakeup = (needed > idle) ? idle : needed;
65289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		needed -= wakeup;
65389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
65489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		dev_dbg(xpc_chan, "wakeup %d idle kthreads, partid=%d, "
65589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			"channel=%d\n", wakeup, ch->partid, ch->number);
65689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
65789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		/* only wakeup the requested number of kthreads */
65889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		wake_up_nr(&ch->idle_wq, wakeup);
65989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	}
66089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
66189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	if (needed <= 0) {
66289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		return;
66389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	}
66489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
66589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	if (needed + assigned > ch->kthreads_assigned_limit) {
66689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		needed = ch->kthreads_assigned_limit - assigned;
66789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		// >>>should never be less than 0
66889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		if (needed <= 0) {
66989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			return;
67089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		}
67189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	}
67289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
67389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	dev_dbg(xpc_chan, "create %d new kthreads, partid=%d, channel=%d\n",
67489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		needed, ch->partid, ch->number);
67589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
676a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson	xpc_create_kthreads(ch, needed, 0);
67789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson}
67889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
67989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
68089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson/*
68189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * This function is where XPC's kthreads wait for messages to deliver.
68289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson */
68389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonstatic void
68489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonxpc_kthread_waitmsgs(struct xpc_partition *part, struct xpc_channel *ch)
68589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson{
68689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	do {
68789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		/* deliver messages to their intended recipients */
68889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
68989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		while ((volatile s64) ch->w_local_GP.get <
69089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson				(volatile s64) ch->w_remote_GP.put &&
69189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson					!((volatile u32) ch->flags &
69289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson						XPC_C_DISCONNECTING)) {
69389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			xpc_deliver_msg(ch);
69489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		}
69589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
69689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		if (atomic_inc_return(&ch->kthreads_idle) >
69789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson						ch->kthreads_idle_limit) {
69889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			/* too many idle kthreads on this channel */
69989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			atomic_dec(&ch->kthreads_idle);
70089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			break;
70189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		}
70289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
70389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		dev_dbg(xpc_chan, "idle kthread calling "
70489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			"wait_event_interruptible_exclusive()\n");
70589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
70689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		(void) wait_event_interruptible_exclusive(ch->idle_wq,
70789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson				((volatile s64) ch->w_local_GP.get <
70889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson					(volatile s64) ch->w_remote_GP.put ||
70989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson				((volatile u32) ch->flags &
71089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson						XPC_C_DISCONNECTING)));
71189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
71289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		atomic_dec(&ch->kthreads_idle);
71389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
71489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	} while (!((volatile u32) ch->flags & XPC_C_DISCONNECTING));
71589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson}
71689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
71789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
71889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonstatic int
71989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonxpc_daemonize_kthread(void *args)
72089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson{
72189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	partid_t partid = XPC_UNPACK_ARG1(args);
72289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	u16 ch_number = XPC_UNPACK_ARG2(args);
72389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	struct xpc_partition *part = &xpc_partitions[partid];
72489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	struct xpc_channel *ch;
72589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	int n_needed;
726e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson	unsigned long irq_flags;
72789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
72889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
72989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	daemonize("xpc%02dc%d", partid, ch_number);
73089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
73189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	dev_dbg(xpc_chan, "kthread starting, partid=%d, channel=%d\n",
73289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		partid, ch_number);
73389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
73489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	ch = &part->channels[ch_number];
73589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
73689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	if (!(ch->flags & XPC_C_DISCONNECTING)) {
73789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
73889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		/* let registerer know that connection has been established */
73989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
740e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson		spin_lock_irqsave(&ch->lock, irq_flags);
7414c2cd96696ae0896ce4bcf725b9f0eaffafeb640Dean Nelson		if (!(ch->flags & XPC_C_CONNECTEDCALLOUT)) {
7424c2cd96696ae0896ce4bcf725b9f0eaffafeb640Dean Nelson			ch->flags |= XPC_C_CONNECTEDCALLOUT;
743e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson			spin_unlock_irqrestore(&ch->lock, irq_flags);
744e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson
74589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			xpc_connected_callout(ch);
74689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
7474c2cd96696ae0896ce4bcf725b9f0eaffafeb640Dean Nelson			spin_lock_irqsave(&ch->lock, irq_flags);
7484c2cd96696ae0896ce4bcf725b9f0eaffafeb640Dean Nelson			ch->flags |= XPC_C_CONNECTEDCALLOUT_MADE;
7494c2cd96696ae0896ce4bcf725b9f0eaffafeb640Dean Nelson			spin_unlock_irqrestore(&ch->lock, irq_flags);
7504c2cd96696ae0896ce4bcf725b9f0eaffafeb640Dean Nelson
75189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			/*
75289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			 * It is possible that while the callout was being
75389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			 * made that the remote partition sent some messages.
75489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			 * If that is the case, we may need to activate
75589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			 * additional kthreads to help deliver them. We only
75689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			 * need one less than total #of messages to deliver.
75789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			 */
75889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			n_needed = ch->w_remote_GP.put - ch->w_local_GP.get - 1;
75989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			if (n_needed > 0 &&
76089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson					!(ch->flags & XPC_C_DISCONNECTING)) {
76189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson				xpc_activate_kthreads(ch, n_needed);
76289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			}
763e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson		} else {
764e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson			spin_unlock_irqrestore(&ch->lock, irq_flags);
76589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		}
76689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
76789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		xpc_kthread_waitmsgs(part, ch);
76889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	}
76989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
770a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson	/* let registerer know that connection is disconnecting */
771e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson
772a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson	spin_lock_irqsave(&ch->lock, irq_flags);
773a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson	if ((ch->flags & XPC_C_CONNECTEDCALLOUT_MADE) &&
774a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson			!(ch->flags & XPC_C_DISCONNECTINGCALLOUT)) {
775a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson		ch->flags |= XPC_C_DISCONNECTINGCALLOUT;
7764c2cd96696ae0896ce4bcf725b9f0eaffafeb640Dean Nelson		spin_unlock_irqrestore(&ch->lock, irq_flags);
777a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson
778a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson		xpc_disconnect_callout(ch, xpcDisconnecting);
779a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson
780a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson		spin_lock_irqsave(&ch->lock, irq_flags);
781a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson		ch->flags |= XPC_C_DISCONNECTINGCALLOUT_MADE;
782a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson	}
783a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson	spin_unlock_irqrestore(&ch->lock, irq_flags);
784a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson
785a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson	if (atomic_dec_return(&ch->kthreads_assigned) == 0) {
786a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson		if (atomic_dec_return(&part->nchannels_engaged) == 0) {
787a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson			xpc_mark_partition_disengaged(part);
788a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson			xpc_IPI_send_disengage(part);
789a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson		}
79089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	}
79189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
79289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	xpc_msgqueue_deref(ch);
79389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
79489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	dev_dbg(xpc_chan, "kthread exiting, partid=%d, channel=%d\n",
79589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		partid, ch_number);
79689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
79789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	xpc_part_deref(part);
79889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	return 0;
79989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson}
80089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
80189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
80289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson/*
80389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * For each partition that XPC has established communications with, there is
80489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * a minimum of one kernel thread assigned to perform any operation that
80589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * may potentially sleep or block (basically the callouts to the asynchronous
80689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * functions registered via xpc_connect()).
80789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *
80889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * Additional kthreads are created and destroyed by XPC as the workload
80989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * demands.
81089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *
81189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * A kthread is assigned to one of the active channels that exists for a given
81289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * partition.
81389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson */
81489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonvoid
815a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelsonxpc_create_kthreads(struct xpc_channel *ch, int needed,
816a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson			int ignore_disconnecting)
81789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson{
81889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	unsigned long irq_flags;
81989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	pid_t pid;
82089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	u64 args = XPC_PACK_ARGS(ch->partid, ch->number);
821a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson	struct xpc_partition *part = &xpc_partitions[ch->partid];
82289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
82389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
82489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	while (needed-- > 0) {
825e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson
826e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson		/*
827e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson		 * The following is done on behalf of the newly created
828e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson		 * kthread. That kthread is responsible for doing the
829e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson		 * counterpart to the following before it exits.
830e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson		 */
831a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson		if (ignore_disconnecting) {
832a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson			if (!atomic_inc_not_zero(&ch->kthreads_assigned)) {
833a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson				/* kthreads assigned had gone to zero */
834a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson				BUG_ON(!(ch->flags &
835a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson					XPC_C_DISCONNECTINGCALLOUT_MADE));
836a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson				break;
837a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson			}
838a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson
839a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson		} else if (ch->flags & XPC_C_DISCONNECTING) {
840a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson			break;
841a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson
842a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson		} else if (atomic_inc_return(&ch->kthreads_assigned) == 1) {
843a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson			if (atomic_inc_return(&part->nchannels_engaged) == 1)
844a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson				xpc_mark_partition_engaged(part);
845a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson		}
846e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson		(void) xpc_part_ref(part);
847e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson		xpc_msgqueue_ref(ch);
848e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson
84989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		pid = kernel_thread(xpc_daemonize_kthread, (void *) args, 0);
85089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		if (pid < 0) {
85189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			/* the fork failed */
852a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson
853a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson			/*
854a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson			 * NOTE: if (ignore_disconnecting &&
855a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson			 * !(ch->flags & XPC_C_DISCONNECTINGCALLOUT)) is true,
856a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson			 * then we'll deadlock if all other kthreads assigned
857a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson			 * to this channel are blocked in the channel's
858a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson			 * registerer, because the only thing that will unblock
859a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson			 * them is the xpcDisconnecting callout that this
860a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson			 * failed kernel_thread would have made.
861a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson			 */
862a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson
863e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson			if (atomic_dec_return(&ch->kthreads_assigned) == 0 &&
864e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson			    atomic_dec_return(&part->nchannels_engaged) == 0) {
865e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson				xpc_mark_partition_disengaged(part);
866e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson				xpc_IPI_send_disengage(part);
867e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson			}
868e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson			xpc_msgqueue_deref(ch);
869e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson			xpc_part_deref(part);
87089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
87189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			if (atomic_read(&ch->kthreads_assigned) <
87289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson						ch->kthreads_idle_limit) {
87389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson				/*
87489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson				 * Flag this as an error only if we have an
87589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson				 * insufficient #of kthreads for the channel
87689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson				 * to function.
87789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson				 */
87889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson				spin_lock_irqsave(&ch->lock, irq_flags);
87989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson				XPC_DISCONNECT_CHANNEL(ch, xpcLackOfResources,
88089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson								&irq_flags);
88189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson				spin_unlock_irqrestore(&ch->lock, irq_flags);
88289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			}
88389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			break;
88489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		}
88589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
88689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		ch->kthreads_created++;	// >>> temporary debug only!!!
88789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	}
88889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson}
88989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
89089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
89189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonvoid
89289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonxpc_disconnect_wait(int ch_number)
89389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson{
894a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson	unsigned long irq_flags;
89589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	partid_t partid;
89689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	struct xpc_partition *part;
89789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	struct xpc_channel *ch;
898e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson	int wakeup_channel_mgr;
89989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
90089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
90189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	/* now wait for all callouts to the caller's function to cease */
90289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) {
90389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		part = &xpc_partitions[partid];
90489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
905e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson		if (!xpc_part_ref(part)) {
906e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson			continue;
907e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson		}
90889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
909e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson		ch = &part->channels[ch_number];
91089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
911e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson		if (!(ch->flags & XPC_C_WDISCONNECT)) {
91289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			xpc_part_deref(part);
913e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson			continue;
91489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		}
915e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson
916f9e505a9a03df5acace6e758c8d12982635a1c64Jes Sorensen		wait_for_completion(&ch->wdisconnect_wait);
917e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson
918e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson		spin_lock_irqsave(&ch->lock, irq_flags);
919e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson		DBUG_ON(!(ch->flags & XPC_C_DISCONNECTED));
920e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson		wakeup_channel_mgr = 0;
921e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson
922e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson		if (ch->delayed_IPI_flags) {
923e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson			if (part->act_state != XPC_P_DEACTIVATING) {
924e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson				spin_lock(&part->IPI_lock);
925e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson				XPC_SET_IPI_FLAGS(part->local_IPI_amo,
926e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson					ch->number, ch->delayed_IPI_flags);
927e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson				spin_unlock(&part->IPI_lock);
928e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson				wakeup_channel_mgr = 1;
929e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson			}
930e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson			ch->delayed_IPI_flags = 0;
93189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		}
932e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson
933e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson		ch->flags &= ~XPC_C_WDISCONNECT;
934e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson		spin_unlock_irqrestore(&ch->lock, irq_flags);
935e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson
936e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson		if (wakeup_channel_mgr) {
937e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson			xpc_wakeup_channel_mgr(part);
938e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson		}
939e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson
940e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson		xpc_part_deref(part);
94189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	}
94289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson}
94389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
94489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
94589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonstatic void
946a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelsonxpc_do_exit(enum xpc_retval reason)
94789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson{
94889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	partid_t partid;
9491ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson	int active_part_count, printed_waiting_msg = 0;
95089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	struct xpc_partition *part;
9511ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson	unsigned long printmsg_time, disengage_request_timeout = 0;
95289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
95389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
954a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson	/* a 'rmmod XPC' and a 'reboot' cannot both end up here together */
955a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson	DBUG_ON(xpc_exiting == 1);
95689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
95789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	/*
958a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson	 * Let the heartbeat checker thread and the discovery thread
959a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson	 * (if one is running) know that they should exit. Also wake up
960a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson	 * the heartbeat checker thread in case it's sleeping.
96189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 */
96289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	xpc_exiting = 1;
96389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	wake_up_interruptible(&xpc_act_IRQ_wq);
96489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
965a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson	/* ignore all incoming interrupts */
966a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson	free_irq(SGI_XPC_ACTIVATE, NULL);
96789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
968e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson	/* wait for the discovery thread to exit */
969f9e505a9a03df5acace6e758c8d12982635a1c64Jes Sorensen	wait_for_completion(&xpc_discovery_exited);
97089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
971e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson	/* wait for the heartbeat checker thread to exit */
972f9e505a9a03df5acace6e758c8d12982635a1c64Jes Sorensen	wait_for_completion(&xpc_hb_checker_exited);
97389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
97489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
975a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson	/* sleep for a 1/3 of a second or so */
976a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson	(void) msleep_interruptible(300);
97789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
97889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
97989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	/* wait for all partitions to become inactive */
98089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
9811ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson	printmsg_time = jiffies + (XPC_DISENGAGE_PRINTMSG_INTERVAL * HZ);
9821ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson	xpc_disengage_request_timedout = 0;
983a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson
98489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	do {
98589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		active_part_count = 0;
98689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
98789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) {
98889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			part = &xpc_partitions[partid];
98989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
990a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson			if (xpc_partition_disengaged(part) &&
991a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson					part->act_state == XPC_P_INACTIVE) {
992a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson				continue;
99389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			}
994a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson
995a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson			active_part_count++;
996a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson
997a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson			XPC_DEACTIVATE_PARTITION(part, reason);
99889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
9991ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson			if (part->disengage_request_timeout >
10001ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson						disengage_request_timeout) {
10011ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson				disengage_request_timeout =
10021ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson						part->disengage_request_timeout;
10031ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson			}
1004a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson		}
100589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
10061ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson		if (xpc_partition_engaged(-1UL)) {
10071ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson			if (time_after(jiffies, printmsg_time)) {
10081ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson				dev_info(xpc_part, "waiting for remote "
10091ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson					"partitions to disengage, timeout in "
10101ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson					"%ld seconds\n",
10111ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson					(disengage_request_timeout - jiffies)
10121ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson									/ HZ);
10131ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson				printmsg_time = jiffies +
1014a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson					(XPC_DISENGAGE_PRINTMSG_INTERVAL * HZ);
10151ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson				printed_waiting_msg = 1;
10161ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson			}
10171ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson
10181ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson		} else if (active_part_count > 0) {
10191ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson			if (printed_waiting_msg) {
10201ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson				dev_info(xpc_part, "waiting for local partition"
10211ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson					" to disengage\n");
10221ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson				printed_waiting_msg = 0;
10231ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson			}
10241ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson
10251ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson		} else {
10261ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson			if (!xpc_disengage_request_timedout) {
10271ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson				dev_info(xpc_part, "all partitions have "
10281ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson					"disengaged\n");
10291ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson			}
10301ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson			break;
103189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		}
103289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
1033a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson		/* sleep for a 1/3 of a second or so */
1034a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson		(void) msleep_interruptible(300);
1035a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson
1036a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson	} while (1);
1037a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson
1038a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson	DBUG_ON(xpc_partition_engaged(-1UL));
1039a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson
1040a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson
1041a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson	/* indicate to others that our reserved page is uninitialized */
1042a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson	xpc_rsvd_page->vars_pa = 0;
1043a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson
1044a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson	/* now it's time to eliminate our heartbeat */
1045a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson	del_timer_sync(&xpc_hb_timer);
1046e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson	DBUG_ON(xpc_vars->heartbeating_to_mask != 0);
104789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
10480752c670d83362609c7f3f59ffa0e180709c60c2Dean Nelson	if (reason == xpcUnloading) {
10490752c670d83362609c7f3f59ffa0e180709c60c2Dean Nelson		/* take ourselves off of the reboot_notifier_list */
10500752c670d83362609c7f3f59ffa0e180709c60c2Dean Nelson		(void) unregister_reboot_notifier(&xpc_reboot_notifier);
105189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
10520752c670d83362609c7f3f59ffa0e180709c60c2Dean Nelson		/* take ourselves off of the die_notifier list */
10530752c670d83362609c7f3f59ffa0e180709c60c2Dean Nelson		(void) unregister_die_notifier(&xpc_die_notifier);
10540752c670d83362609c7f3f59ffa0e180709c60c2Dean Nelson	}
1055780d09e895032207a6b070a44d392a3c60574b70Dean Nelson
105689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	/* close down protections for IPI operations */
105789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	xpc_restrict_IPI_ops();
105889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
105989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
106089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	/* clear the interface to XPC's functions */
106189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	xpc_clear_interface();
106289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
106389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	if (xpc_sysctl) {
106489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		unregister_sysctl_table(xpc_sysctl);
106589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	}
10667682a4c624e0011b5f3e8dd3021dc54961260d97Dean Nelson
10677682a4c624e0011b5f3e8dd3021dc54961260d97Dean Nelson	kfree(xpc_remote_copy_buffer_base);
106889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson}
106989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
107089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
1071a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson/*
1072d6ad033a88b42420ddb6c62c95e42f88d862b246Dean Nelson * This function is called when the system is being rebooted.
1073d6ad033a88b42420ddb6c62c95e42f88d862b246Dean Nelson */
1074d6ad033a88b42420ddb6c62c95e42f88d862b246Dean Nelsonstatic int
1075d6ad033a88b42420ddb6c62c95e42f88d862b246Dean Nelsonxpc_system_reboot(struct notifier_block *nb, unsigned long event, void *unused)
1076d6ad033a88b42420ddb6c62c95e42f88d862b246Dean Nelson{
1077d6ad033a88b42420ddb6c62c95e42f88d862b246Dean Nelson	enum xpc_retval reason;
1078d6ad033a88b42420ddb6c62c95e42f88d862b246Dean Nelson
1079d6ad033a88b42420ddb6c62c95e42f88d862b246Dean Nelson
1080d6ad033a88b42420ddb6c62c95e42f88d862b246Dean Nelson	switch (event) {
1081d6ad033a88b42420ddb6c62c95e42f88d862b246Dean Nelson	case SYS_RESTART:
1082d6ad033a88b42420ddb6c62c95e42f88d862b246Dean Nelson		reason = xpcSystemReboot;
1083d6ad033a88b42420ddb6c62c95e42f88d862b246Dean Nelson		break;
1084d6ad033a88b42420ddb6c62c95e42f88d862b246Dean Nelson	case SYS_HALT:
1085d6ad033a88b42420ddb6c62c95e42f88d862b246Dean Nelson		reason = xpcSystemHalt;
1086d6ad033a88b42420ddb6c62c95e42f88d862b246Dean Nelson		break;
1087d6ad033a88b42420ddb6c62c95e42f88d862b246Dean Nelson	case SYS_POWER_OFF:
1088d6ad033a88b42420ddb6c62c95e42f88d862b246Dean Nelson		reason = xpcSystemPoweroff;
1089d6ad033a88b42420ddb6c62c95e42f88d862b246Dean Nelson		break;
1090d6ad033a88b42420ddb6c62c95e42f88d862b246Dean Nelson	default:
1091d6ad033a88b42420ddb6c62c95e42f88d862b246Dean Nelson		reason = xpcSystemGoingDown;
1092d6ad033a88b42420ddb6c62c95e42f88d862b246Dean Nelson	}
1093d6ad033a88b42420ddb6c62c95e42f88d862b246Dean Nelson
1094d6ad033a88b42420ddb6c62c95e42f88d862b246Dean Nelson	xpc_do_exit(reason);
1095d6ad033a88b42420ddb6c62c95e42f88d862b246Dean Nelson	return NOTIFY_DONE;
1096d6ad033a88b42420ddb6c62c95e42f88d862b246Dean Nelson}
1097d6ad033a88b42420ddb6c62c95e42f88d862b246Dean Nelson
1098d6ad033a88b42420ddb6c62c95e42f88d862b246Dean Nelson
1099d6ad033a88b42420ddb6c62c95e42f88d862b246Dean Nelson/*
1100d6ad033a88b42420ddb6c62c95e42f88d862b246Dean Nelson * Notify other partitions to disengage from all references to our memory.
1101780d09e895032207a6b070a44d392a3c60574b70Dean Nelson */
1102780d09e895032207a6b070a44d392a3c60574b70Dean Nelsonstatic void
1103780d09e895032207a6b070a44d392a3c60574b70Dean Nelsonxpc_die_disengage(void)
1104780d09e895032207a6b070a44d392a3c60574b70Dean Nelson{
1105780d09e895032207a6b070a44d392a3c60574b70Dean Nelson	struct xpc_partition *part;
1106780d09e895032207a6b070a44d392a3c60574b70Dean Nelson	partid_t partid;
1107780d09e895032207a6b070a44d392a3c60574b70Dean Nelson	unsigned long engaged;
11081ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson	long time, printmsg_time, disengage_request_timeout;
1109780d09e895032207a6b070a44d392a3c60574b70Dean Nelson
1110780d09e895032207a6b070a44d392a3c60574b70Dean Nelson
1111780d09e895032207a6b070a44d392a3c60574b70Dean Nelson	/* keep xpc_hb_checker thread from doing anything (just in case) */
1112780d09e895032207a6b070a44d392a3c60574b70Dean Nelson	xpc_exiting = 1;
1113780d09e895032207a6b070a44d392a3c60574b70Dean Nelson
1114780d09e895032207a6b070a44d392a3c60574b70Dean Nelson	xpc_vars->heartbeating_to_mask = 0;  /* indicate we're deactivated */
1115780d09e895032207a6b070a44d392a3c60574b70Dean Nelson
1116780d09e895032207a6b070a44d392a3c60574b70Dean Nelson	for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) {
1117780d09e895032207a6b070a44d392a3c60574b70Dean Nelson		part = &xpc_partitions[partid];
1118780d09e895032207a6b070a44d392a3c60574b70Dean Nelson
1119780d09e895032207a6b070a44d392a3c60574b70Dean Nelson		if (!XPC_SUPPORTS_DISENGAGE_REQUEST(part->
1120780d09e895032207a6b070a44d392a3c60574b70Dean Nelson							remote_vars_version)) {
1121780d09e895032207a6b070a44d392a3c60574b70Dean Nelson
1122780d09e895032207a6b070a44d392a3c60574b70Dean Nelson			/* just in case it was left set by an earlier XPC */
1123780d09e895032207a6b070a44d392a3c60574b70Dean Nelson			xpc_clear_partition_engaged(1UL << partid);
1124780d09e895032207a6b070a44d392a3c60574b70Dean Nelson			continue;
1125780d09e895032207a6b070a44d392a3c60574b70Dean Nelson		}
1126780d09e895032207a6b070a44d392a3c60574b70Dean Nelson
1127780d09e895032207a6b070a44d392a3c60574b70Dean Nelson		if (xpc_partition_engaged(1UL << partid) ||
1128780d09e895032207a6b070a44d392a3c60574b70Dean Nelson					part->act_state != XPC_P_INACTIVE) {
1129780d09e895032207a6b070a44d392a3c60574b70Dean Nelson			xpc_request_partition_disengage(part);
1130780d09e895032207a6b070a44d392a3c60574b70Dean Nelson			xpc_mark_partition_disengaged(part);
1131780d09e895032207a6b070a44d392a3c60574b70Dean Nelson			xpc_IPI_send_disengage(part);
1132780d09e895032207a6b070a44d392a3c60574b70Dean Nelson		}
1133780d09e895032207a6b070a44d392a3c60574b70Dean Nelson	}
1134780d09e895032207a6b070a44d392a3c60574b70Dean Nelson
11351ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson	time = rtc_time();
11361ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson	printmsg_time = time +
11371ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson		(XPC_DISENGAGE_PRINTMSG_INTERVAL * sn_rtc_cycles_per_second);
11381ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson	disengage_request_timeout = time +
1139780d09e895032207a6b070a44d392a3c60574b70Dean Nelson		(xpc_disengage_request_timelimit * sn_rtc_cycles_per_second);
1140780d09e895032207a6b070a44d392a3c60574b70Dean Nelson
1141780d09e895032207a6b070a44d392a3c60574b70Dean Nelson	/* wait for all other partitions to disengage from us */
1142780d09e895032207a6b070a44d392a3c60574b70Dean Nelson
11431ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson	while (1) {
11441ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson		engaged = xpc_partition_engaged(-1UL);
11451ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson		if (!engaged) {
11461ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson			dev_info(xpc_part, "all partitions have disengaged\n");
11471ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson			break;
11481ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson		}
1149780d09e895032207a6b070a44d392a3c60574b70Dean Nelson
11501ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson		time = rtc_time();
11511ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson		if (time >= disengage_request_timeout) {
11521ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson			for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) {
11531ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson				if (engaged & (1UL << partid)) {
11541ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson					dev_info(xpc_part, "disengage from "
11551ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson						"remote partition %d timed "
11561ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson						"out\n", partid);
11571ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson				}
11581ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson			}
11591ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson			break;
11601ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson		}
11611ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson
11621ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson		if (time >= printmsg_time) {
1163780d09e895032207a6b070a44d392a3c60574b70Dean Nelson			dev_info(xpc_part, "waiting for remote partitions to "
11641ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson				"disengage, timeout in %ld seconds\n",
11651ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson				(disengage_request_timeout - time) /
11661ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson						sn_rtc_cycles_per_second);
11671ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson			printmsg_time = time +
11681ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson					(XPC_DISENGAGE_PRINTMSG_INTERVAL *
1169780d09e895032207a6b070a44d392a3c60574b70Dean Nelson						sn_rtc_cycles_per_second);
1170780d09e895032207a6b070a44d392a3c60574b70Dean Nelson		}
1171780d09e895032207a6b070a44d392a3c60574b70Dean Nelson	}
1172780d09e895032207a6b070a44d392a3c60574b70Dean Nelson}
1173780d09e895032207a6b070a44d392a3c60574b70Dean Nelson
1174780d09e895032207a6b070a44d392a3c60574b70Dean Nelson
1175780d09e895032207a6b070a44d392a3c60574b70Dean Nelson/*
11761f4674b2d5f63bac4c393ac4de1d6c1b6b72c09cDean Nelson * This function is called when the system is being restarted or halted due
11771f4674b2d5f63bac4c393ac4de1d6c1b6b72c09cDean Nelson * to some sort of system failure. If this is the case we need to notify the
11781f4674b2d5f63bac4c393ac4de1d6c1b6b72c09cDean Nelson * other partitions to disengage from all references to our memory.
11791f4674b2d5f63bac4c393ac4de1d6c1b6b72c09cDean Nelson * This function can also be called when our heartbeater could be offlined
11801f4674b2d5f63bac4c393ac4de1d6c1b6b72c09cDean Nelson * for a time. In this case we need to notify other partitions to not worry
11811f4674b2d5f63bac4c393ac4de1d6c1b6b72c09cDean Nelson * about the lack of a heartbeat.
1182780d09e895032207a6b070a44d392a3c60574b70Dean Nelson */
1183780d09e895032207a6b070a44d392a3c60574b70Dean Nelsonstatic int
1184780d09e895032207a6b070a44d392a3c60574b70Dean Nelsonxpc_system_die(struct notifier_block *nb, unsigned long event, void *unused)
1185780d09e895032207a6b070a44d392a3c60574b70Dean Nelson{
1186780d09e895032207a6b070a44d392a3c60574b70Dean Nelson	switch (event) {
1187780d09e895032207a6b070a44d392a3c60574b70Dean Nelson	case DIE_MACHINE_RESTART:
1188780d09e895032207a6b070a44d392a3c60574b70Dean Nelson	case DIE_MACHINE_HALT:
1189780d09e895032207a6b070a44d392a3c60574b70Dean Nelson		xpc_die_disengage();
1190780d09e895032207a6b070a44d392a3c60574b70Dean Nelson		break;
11911f4674b2d5f63bac4c393ac4de1d6c1b6b72c09cDean Nelson
11921f4674b2d5f63bac4c393ac4de1d6c1b6b72c09cDean Nelson	case DIE_KDEBUG_ENTER:
11931f4674b2d5f63bac4c393ac4de1d6c1b6b72c09cDean Nelson		/* Should lack of heartbeat be ignored by other partitions? */
11941f4674b2d5f63bac4c393ac4de1d6c1b6b72c09cDean Nelson		if (!xpc_kdebug_ignore) {
11951f4674b2d5f63bac4c393ac4de1d6c1b6b72c09cDean Nelson			break;
11961f4674b2d5f63bac4c393ac4de1d6c1b6b72c09cDean Nelson		}
11971f4674b2d5f63bac4c393ac4de1d6c1b6b72c09cDean Nelson		/* fall through */
1198780d09e895032207a6b070a44d392a3c60574b70Dean Nelson	case DIE_MCA_MONARCH_ENTER:
1199780d09e895032207a6b070a44d392a3c60574b70Dean Nelson	case DIE_INIT_MONARCH_ENTER:
1200780d09e895032207a6b070a44d392a3c60574b70Dean Nelson		xpc_vars->heartbeat++;
1201780d09e895032207a6b070a44d392a3c60574b70Dean Nelson		xpc_vars->heartbeat_offline = 1;
1202780d09e895032207a6b070a44d392a3c60574b70Dean Nelson		break;
12031f4674b2d5f63bac4c393ac4de1d6c1b6b72c09cDean Nelson
12041f4674b2d5f63bac4c393ac4de1d6c1b6b72c09cDean Nelson	case DIE_KDEBUG_LEAVE:
12051f4674b2d5f63bac4c393ac4de1d6c1b6b72c09cDean Nelson		/* Is lack of heartbeat being ignored by other partitions? */
12061f4674b2d5f63bac4c393ac4de1d6c1b6b72c09cDean Nelson		if (!xpc_kdebug_ignore) {
12071f4674b2d5f63bac4c393ac4de1d6c1b6b72c09cDean Nelson			break;
12081f4674b2d5f63bac4c393ac4de1d6c1b6b72c09cDean Nelson		}
12091f4674b2d5f63bac4c393ac4de1d6c1b6b72c09cDean Nelson		/* fall through */
1210780d09e895032207a6b070a44d392a3c60574b70Dean Nelson	case DIE_MCA_MONARCH_LEAVE:
1211780d09e895032207a6b070a44d392a3c60574b70Dean Nelson	case DIE_INIT_MONARCH_LEAVE:
1212780d09e895032207a6b070a44d392a3c60574b70Dean Nelson		xpc_vars->heartbeat++;
1213780d09e895032207a6b070a44d392a3c60574b70Dean Nelson		xpc_vars->heartbeat_offline = 0;
1214780d09e895032207a6b070a44d392a3c60574b70Dean Nelson		break;
1215780d09e895032207a6b070a44d392a3c60574b70Dean Nelson	}
1216780d09e895032207a6b070a44d392a3c60574b70Dean Nelson
1217780d09e895032207a6b070a44d392a3c60574b70Dean Nelson	return NOTIFY_DONE;
1218780d09e895032207a6b070a44d392a3c60574b70Dean Nelson}
1219780d09e895032207a6b070a44d392a3c60574b70Dean Nelson
1220780d09e895032207a6b070a44d392a3c60574b70Dean Nelson
122189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonint __init
122289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonxpc_init(void)
122389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson{
122489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	int ret;
122589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	partid_t partid;
122689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	struct xpc_partition *part;
122789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	pid_t pid;
12287682a4c624e0011b5f3e8dd3021dc54961260d97Dean Nelson	size_t buf_size;
122989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
123089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
1231408865ce4829376120489ac8011b72125453dcffDean Nelson	if (!ia64_platform_is("sn2")) {
1232408865ce4829376120489ac8011b72125453dcffDean Nelson		return -ENODEV;
1233408865ce4829376120489ac8011b72125453dcffDean Nelson	}
1234408865ce4829376120489ac8011b72125453dcffDean Nelson
12357682a4c624e0011b5f3e8dd3021dc54961260d97Dean Nelson
12367682a4c624e0011b5f3e8dd3021dc54961260d97Dean Nelson	buf_size = max(XPC_RP_VARS_SIZE,
12377682a4c624e0011b5f3e8dd3021dc54961260d97Dean Nelson				XPC_RP_HEADER_SIZE + XP_NASID_MASK_BYTES);
12387682a4c624e0011b5f3e8dd3021dc54961260d97Dean Nelson	xpc_remote_copy_buffer = xpc_kmalloc_cacheline_aligned(buf_size,
12397682a4c624e0011b5f3e8dd3021dc54961260d97Dean Nelson				     GFP_KERNEL, &xpc_remote_copy_buffer_base);
12407682a4c624e0011b5f3e8dd3021dc54961260d97Dean Nelson	if (xpc_remote_copy_buffer == NULL)
12417682a4c624e0011b5f3e8dd3021dc54961260d97Dean Nelson		return -ENOMEM;
124289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
124389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	snprintf(xpc_part->bus_id, BUS_ID_SIZE, "part");
124489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	snprintf(xpc_chan->bus_id, BUS_ID_SIZE, "chan");
124589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
12460b4d414714f0d2f922d39424b0c5c82ad900a381Eric W. Biederman	xpc_sysctl = register_sysctl_table(xpc_sys_dir);
124789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
124889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	/*
124989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 * The first few fields of each entry of xpc_partitions[] need to
125089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 * be initialized now so that calls to xpc_connect() and
125189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 * xpc_disconnect() can be made prior to the activation of any remote
125289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 * partition. NOTE THAT NONE OF THE OTHER FIELDS BELONGING TO THESE
125389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 * ENTRIES ARE MEANINGFUL UNTIL AFTER AN ENTRY'S CORRESPONDING
125489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 * PARTITION HAS BEEN ACTIVATED.
125589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 */
125689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) {
125789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		part = &xpc_partitions[partid];
125889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
125989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		DBUG_ON((u64) part != L1_CACHE_ALIGN((u64) part));
126089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
126189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		part->act_IRQ_rcvd = 0;
126289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		spin_lock_init(&part->act_lock);
126389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		part->act_state = XPC_P_INACTIVE;
126489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		XPC_SET_REASON(part, 0, 0);
1265a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson
1266a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson		init_timer(&part->disengage_request_timer);
1267a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson		part->disengage_request_timer.function =
1268a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson				xpc_timeout_partition_disengage_request;
1269a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson		part->disengage_request_timer.data = (unsigned long) part;
1270a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson
127189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		part->setup_state = XPC_P_UNSET;
127289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		init_waitqueue_head(&part->teardown_wq);
127389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		atomic_set(&part->references, 0);
127489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	}
127589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
127689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	/*
127789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 * Open up protections for IPI operations (and AMO operations on
127889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 * Shub 1.1 systems).
127989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 */
128089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	xpc_allow_IPI_ops();
128189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
128289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	/*
128389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 * Interrupts being processed will increment this atomic variable and
128489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 * awaken the heartbeat thread which will process the interrupts.
128589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 */
128689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	atomic_set(&xpc_act_IRQ_rcvd, 0);
128789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
128889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	/*
128989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 * This is safe to do before the xpc_hb_checker thread has started
129089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 * because the handler releases a wait queue.  If an interrupt is
129189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 * received before the thread is waiting, it will not go to sleep,
129289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 * but rather immediately process the interrupt.
129389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 */
129489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	ret = request_irq(SGI_XPC_ACTIVATE, xpc_act_IRQ_handler, 0,
129589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson							"xpc hb", NULL);
129689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	if (ret != 0) {
129789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		dev_err(xpc_part, "can't register ACTIVATE IRQ handler, "
129889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			"errno=%d\n", -ret);
129989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
130089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		xpc_restrict_IPI_ops();
130189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
130289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		if (xpc_sysctl) {
130389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			unregister_sysctl_table(xpc_sysctl);
130489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		}
13057682a4c624e0011b5f3e8dd3021dc54961260d97Dean Nelson
13067682a4c624e0011b5f3e8dd3021dc54961260d97Dean Nelson		kfree(xpc_remote_copy_buffer_base);
130789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		return -EBUSY;
130889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	}
130989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
131089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	/*
131189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 * Fill the partition reserved page with the information needed by
131289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 * other partitions to discover we are alive and establish initial
131389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 * communications.
131489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 */
131589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	xpc_rsvd_page = xpc_rsvd_page_init();
131689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	if (xpc_rsvd_page == NULL) {
131789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		dev_err(xpc_part, "could not setup our reserved page\n");
131889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
131989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		free_irq(SGI_XPC_ACTIVATE, NULL);
132089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		xpc_restrict_IPI_ops();
132189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
132289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		if (xpc_sysctl) {
132389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			unregister_sysctl_table(xpc_sysctl);
132489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		}
13257682a4c624e0011b5f3e8dd3021dc54961260d97Dean Nelson
13267682a4c624e0011b5f3e8dd3021dc54961260d97Dean Nelson		kfree(xpc_remote_copy_buffer_base);
132789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		return -EBUSY;
132889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	}
132989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
133089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
1331a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson	/* add ourselves to the reboot_notifier_list */
1332a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson	ret = register_reboot_notifier(&xpc_reboot_notifier);
1333a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson	if (ret != 0) {
1334a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson		dev_warn(xpc_part, "can't register reboot notifier\n");
1335a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson	}
1336a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson
13371eeb66a1bb973534dc3d064920a5ca683823372eChristoph Hellwig	/* add ourselves to the die_notifier list */
1338780d09e895032207a6b070a44d392a3c60574b70Dean Nelson	ret = register_die_notifier(&xpc_die_notifier);
1339780d09e895032207a6b070a44d392a3c60574b70Dean Nelson	if (ret != 0) {
1340780d09e895032207a6b070a44d392a3c60574b70Dean Nelson		dev_warn(xpc_part, "can't register die notifier\n");
1341780d09e895032207a6b070a44d392a3c60574b70Dean Nelson	}
1342780d09e895032207a6b070a44d392a3c60574b70Dean Nelson
134389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	init_timer(&xpc_hb_timer);
134489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	xpc_hb_timer.function = xpc_hb_beater;
134589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
134689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	/*
134789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 * The real work-horse behind xpc.  This processes incoming
134889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 * interrupts and monitors remote heartbeats.
134989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 */
135089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	pid = kernel_thread(xpc_hb_checker, NULL, 0);
135189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	if (pid < 0) {
135289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		dev_err(xpc_part, "failed while forking hb check thread\n");
135389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
135489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		/* indicate to others that our reserved page is uninitialized */
135589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		xpc_rsvd_page->vars_pa = 0;
135689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
1357a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson		/* take ourselves off of the reboot_notifier_list */
1358a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson		(void) unregister_reboot_notifier(&xpc_reboot_notifier);
1359a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson
1360780d09e895032207a6b070a44d392a3c60574b70Dean Nelson		/* take ourselves off of the die_notifier list */
1361780d09e895032207a6b070a44d392a3c60574b70Dean Nelson		(void) unregister_die_notifier(&xpc_die_notifier);
1362780d09e895032207a6b070a44d392a3c60574b70Dean Nelson
136389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		del_timer_sync(&xpc_hb_timer);
136489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		free_irq(SGI_XPC_ACTIVATE, NULL);
136589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		xpc_restrict_IPI_ops();
136689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
136789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		if (xpc_sysctl) {
136889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			unregister_sysctl_table(xpc_sysctl);
136989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		}
13707682a4c624e0011b5f3e8dd3021dc54961260d97Dean Nelson
13717682a4c624e0011b5f3e8dd3021dc54961260d97Dean Nelson		kfree(xpc_remote_copy_buffer_base);
137289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		return -EBUSY;
137389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	}
137489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
137589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
137689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	/*
137789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 * Startup a thread that will attempt to discover other partitions to
137889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 * activate based on info provided by SAL. This new thread is short
137989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 * lived and will exit once discovery is complete.
138089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 */
138189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	pid = kernel_thread(xpc_initiate_discovery, NULL, 0);
138289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	if (pid < 0) {
138389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		dev_err(xpc_part, "failed while forking discovery thread\n");
138489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
138589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		/* mark this new thread as a non-starter */
1386f9e505a9a03df5acace6e758c8d12982635a1c64Jes Sorensen		complete(&xpc_discovery_exited);
138789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
1388a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson		xpc_do_exit(xpcUnloading);
138989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		return -EBUSY;
139089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	}
139189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
139289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
139389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	/* set the interface to point at XPC's functions */
139489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	xpc_set_interface(xpc_initiate_connect, xpc_initiate_disconnect,
139589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			  xpc_initiate_allocate, xpc_initiate_send,
139689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			  xpc_initiate_send_notify, xpc_initiate_received,
139789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			  xpc_initiate_partid_to_nasids);
139889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
139989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	return 0;
140089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson}
140189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonmodule_init(xpc_init);
140289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
140389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
140489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonvoid __exit
140589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonxpc_exit(void)
140689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson{
1407a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson	xpc_do_exit(xpcUnloading);
140889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson}
140989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonmodule_exit(xpc_exit);
141089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
141189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
141289eb8eb927e324366c3ac0458998aaf9953fc5cdDean NelsonMODULE_AUTHOR("Silicon Graphics, Inc.");
141389eb8eb927e324366c3ac0458998aaf9953fc5cdDean NelsonMODULE_DESCRIPTION("Cross Partition Communication (XPC) support");
141489eb8eb927e324366c3ac0458998aaf9953fc5cdDean NelsonMODULE_LICENSE("GPL");
141589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
141689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonmodule_param(xpc_hb_interval, int, 0);
141789eb8eb927e324366c3ac0458998aaf9953fc5cdDean NelsonMODULE_PARM_DESC(xpc_hb_interval, "Number of seconds between "
141889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		"heartbeat increments.");
141989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
142089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonmodule_param(xpc_hb_check_interval, int, 0);
142189eb8eb927e324366c3ac0458998aaf9953fc5cdDean NelsonMODULE_PARM_DESC(xpc_hb_check_interval, "Number of seconds between "
142289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		"heartbeat checks.");
142389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
1424e54af724c1ae3530c95135157776c9be65cdb747Dean Nelsonmodule_param(xpc_disengage_request_timelimit, int, 0);
1425e54af724c1ae3530c95135157776c9be65cdb747Dean NelsonMODULE_PARM_DESC(xpc_disengage_request_timelimit, "Number of seconds to wait "
1426e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson		"for disengage request to complete.");
1427e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson
14281f4674b2d5f63bac4c393ac4de1d6c1b6b72c09cDean Nelsonmodule_param(xpc_kdebug_ignore, int, 0);
14291f4674b2d5f63bac4c393ac4de1d6c1b6b72c09cDean NelsonMODULE_PARM_DESC(xpc_kdebug_ignore, "Should lack of heartbeat be ignored by "
14301f4674b2d5f63bac4c393ac4de1d6c1b6b72c09cDean Nelson		"other partitions when dropping into kdebug.");
14311f4674b2d5f63bac4c393ac4de1d6c1b6b72c09cDean Nelson
1432