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 *
6a374c57b0764432a80303abee3d1afd1939b5a0aRobin Holt * Copyright (c) 2004-2009 Silicon Graphics, Inc.  All Rights Reserved.
789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson */
889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson/*
1089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * Cross Partition Communication (XPC) support - standard version.
1189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *
1289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *	XPC provides a message passing capability that crosses partition
1389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *	boundaries. This module is made up of two parts:
1489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *
1589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *	    partition	This part detects the presence/absence of other
1689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *			partitions. It provides a heartbeat and monitors
1789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *			the heartbeats of other partitions.
1889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *
1989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *	    channel	This part manages the channels and sends/receives
2089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *			messages across them to/from other partitions.
2189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *
2289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *	There are a couple of additional functions residing in XP, which
2389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *	provide an interface to XPC for its users.
2489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *
2589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *
2689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *	Caveats:
2789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *
287fb5e59d63deda89a8eefdbd5b3c8d622076afd4Dean Nelson *	  . Currently on sn2, we have no way to determine which nasid an IRQ
29c39838ce21ca8e05857ed7f4be5d289011561905Dean Nelson *	    came from. Thus, xpc_send_IRQ_sn2() does a remote amo write
30c39838ce21ca8e05857ed7f4be5d289011561905Dean Nelson *	    followed by an IPI. The amo indicates where data is to be pulled
31c39838ce21ca8e05857ed7f4be5d289011561905Dean Nelson *	    from, so after the IPI arrives, the remote partition checks the amo
32c39838ce21ca8e05857ed7f4be5d289011561905Dean Nelson *	    word. The IPI can actually arrive before the amo however, so other
33c39838ce21ca8e05857ed7f4be5d289011561905Dean Nelson *	    code must periodically check for this case. Also, remote amo
347fb5e59d63deda89a8eefdbd5b3c8d622076afd4Dean Nelson *	    operations do not reliably time out. Thus we do a remote PIO read
357fb5e59d63deda89a8eefdbd5b3c8d622076afd4Dean Nelson *	    solely to know whether the remote partition is down and whether we
367fb5e59d63deda89a8eefdbd5b3c8d622076afd4Dean Nelson *	    should stop sending IPIs to it. This remote PIO read operation is
377fb5e59d63deda89a8eefdbd5b3c8d622076afd4Dean Nelson *	    set up in a special nofault region so SAL knows to ignore (and
38c39838ce21ca8e05857ed7f4be5d289011561905Dean Nelson *	    cleanup) any errors due to the remote amo write, PIO read, and/or
397fb5e59d63deda89a8eefdbd5b3c8d622076afd4Dean Nelson *	    PIO write operations.
4089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *
4189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *	    If/when new hardware solves this IPI problem, we should abandon
4289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *	    the current approach.
4389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *
4489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson */
4589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
4689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson#include <linux/module.h>
475a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
48261f3b4979db88d29fc86aad9f76fbc0c2c6d21aDean Nelson#include <linux/sysctl.h>
49261f3b4979db88d29fc86aad9f76fbc0c2c6d21aDean Nelson#include <linux/device.h>
50699139279d29e36e39d353b0536b510dab2e5ffaNishanth Aravamudan#include <linux/delay.h>
51a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson#include <linux/reboot.h>
521eeb66a1bb973534dc3d064920a5ca683823372eChristoph Hellwig#include <linux/kdebug.h>
532c2b94f93f4732c3b9703ce62627e6187e7d6128Dean Nelson#include <linux/kthread.h>
5445d9ca492e4bd1522d1b5bd125c2908f1cee3d4aDean Nelson#include "xpc.h"
5589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
5689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson/* define two XPC debug device structures to be used with dev_dbg() et al */
5789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
5889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonstruct device_driver xpc_dbg_name = {
5989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	.name = "xpc"
6089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson};
6189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
6289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonstruct device xpc_part_dbg_subname = {
63bb0dc43eeeea6a3ace7fae42e583a9be176eb1f9Kay Sievers	.init_name = "",	/* set to "part" at xpc_init() time */
6489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	.driver = &xpc_dbg_name
6589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson};
6689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
6789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonstruct device xpc_chan_dbg_subname = {
68bb0dc43eeeea6a3ace7fae42e583a9be176eb1f9Kay Sievers	.init_name = "",	/* set to "chan" at xpc_init() time */
6989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	.driver = &xpc_dbg_name
7089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson};
7189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
7289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonstruct device *xpc_part = &xpc_part_dbg_subname;
7389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonstruct device *xpc_chan = &xpc_chan_dbg_subname;
7489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
751f4674b2d5f63bac4c393ac4de1d6c1b6b72c09cDean Nelsonstatic int xpc_kdebug_ignore;
761f4674b2d5f63bac4c393ac4de1d6c1b6b72c09cDean Nelson
7789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson/* systune related variables for /proc/sys directories */
7889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
79a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelsonstatic int xpc_hb_interval = XPC_HB_DEFAULT_INTERVAL;
80a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelsonstatic int xpc_hb_min_interval = 1;
81a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelsonstatic int xpc_hb_max_interval = 10;
8289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
83a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelsonstatic int xpc_hb_check_interval = XPC_HB_CHECK_DEFAULT_INTERVAL;
84a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelsonstatic int xpc_hb_check_min_interval = 10;
85a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelsonstatic int xpc_hb_check_max_interval = 120;
8689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
87a47d5dac9d8481766382f8cf1483dd581df38b99Dean Nelsonint xpc_disengage_timelimit = XPC_DISENGAGE_DEFAULT_TIMELIMIT;
88a47d5dac9d8481766382f8cf1483dd581df38b99Dean Nelsonstatic int xpc_disengage_min_timelimit;	/* = 0 */
89a47d5dac9d8481766382f8cf1483dd581df38b99Dean Nelsonstatic int xpc_disengage_max_timelimit = 120;
9089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
9189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonstatic ctl_table xpc_sys_xpc_hb_dir[] = {
9289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	{
9335190506b1a18eda7df24b285fdcd94dec7800efDean Nelson	 .procname = "hb_interval",
9435190506b1a18eda7df24b285fdcd94dec7800efDean Nelson	 .data = &xpc_hb_interval,
9535190506b1a18eda7df24b285fdcd94dec7800efDean Nelson	 .maxlen = sizeof(int),
9635190506b1a18eda7df24b285fdcd94dec7800efDean Nelson	 .mode = 0644,
976d4561110a3e9fa742aeec6717248a491dfb1878Eric W. Biederman	 .proc_handler = proc_dointvec_minmax,
9835190506b1a18eda7df24b285fdcd94dec7800efDean Nelson	 .extra1 = &xpc_hb_min_interval,
9935190506b1a18eda7df24b285fdcd94dec7800efDean Nelson	 .extra2 = &xpc_hb_max_interval},
10089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	{
10135190506b1a18eda7df24b285fdcd94dec7800efDean Nelson	 .procname = "hb_check_interval",
10235190506b1a18eda7df24b285fdcd94dec7800efDean Nelson	 .data = &xpc_hb_check_interval,
10335190506b1a18eda7df24b285fdcd94dec7800efDean Nelson	 .maxlen = sizeof(int),
10435190506b1a18eda7df24b285fdcd94dec7800efDean Nelson	 .mode = 0644,
1056d4561110a3e9fa742aeec6717248a491dfb1878Eric W. Biederman	 .proc_handler = proc_dointvec_minmax,
10635190506b1a18eda7df24b285fdcd94dec7800efDean Nelson	 .extra1 = &xpc_hb_check_min_interval,
10735190506b1a18eda7df24b285fdcd94dec7800efDean Nelson	 .extra2 = &xpc_hb_check_max_interval},
10868cbf0753681b3f79437f16d2f9a259b9346cf84Eric W. Biederman	{}
10989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson};
11089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonstatic ctl_table xpc_sys_xpc_dir[] = {
11189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	{
11235190506b1a18eda7df24b285fdcd94dec7800efDean Nelson	 .procname = "hb",
11335190506b1a18eda7df24b285fdcd94dec7800efDean Nelson	 .mode = 0555,
11435190506b1a18eda7df24b285fdcd94dec7800efDean Nelson	 .child = xpc_sys_xpc_hb_dir},
115e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson	{
116a47d5dac9d8481766382f8cf1483dd581df38b99Dean Nelson	 .procname = "disengage_timelimit",
117a47d5dac9d8481766382f8cf1483dd581df38b99Dean Nelson	 .data = &xpc_disengage_timelimit,
11835190506b1a18eda7df24b285fdcd94dec7800efDean Nelson	 .maxlen = sizeof(int),
11935190506b1a18eda7df24b285fdcd94dec7800efDean Nelson	 .mode = 0644,
1206d4561110a3e9fa742aeec6717248a491dfb1878Eric W. Biederman	 .proc_handler = proc_dointvec_minmax,
121a47d5dac9d8481766382f8cf1483dd581df38b99Dean Nelson	 .extra1 = &xpc_disengage_min_timelimit,
122a47d5dac9d8481766382f8cf1483dd581df38b99Dean Nelson	 .extra2 = &xpc_disengage_max_timelimit},
12368cbf0753681b3f79437f16d2f9a259b9346cf84Eric W. Biederman	{}
12489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson};
12589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonstatic ctl_table xpc_sys_dir[] = {
12689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	{
12735190506b1a18eda7df24b285fdcd94dec7800efDean Nelson	 .procname = "xpc",
12835190506b1a18eda7df24b285fdcd94dec7800efDean Nelson	 .mode = 0555,
12935190506b1a18eda7df24b285fdcd94dec7800efDean Nelson	 .child = xpc_sys_xpc_dir},
13068cbf0753681b3f79437f16d2f9a259b9346cf84Eric W. Biederman	{}
13189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson};
13289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonstatic struct ctl_table_header *xpc_sysctl;
13389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
134a47d5dac9d8481766382f8cf1483dd581df38b99Dean Nelson/* non-zero if any remote partition disengage was timed out */
135a47d5dac9d8481766382f8cf1483dd581df38b99Dean Nelsonint xpc_disengage_timedout;
13689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
1375b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson/* #of activate IRQs received and not yet processed */
1385b8669dfd110a62a74eea525a009342f73987ea0Dean Nelsonint xpc_activate_IRQ_rcvd;
1395b8669dfd110a62a74eea525a009342f73987ea0Dean NelsonDEFINE_SPINLOCK(xpc_activate_IRQ_rcvd_lock);
14089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
14189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson/* IRQ handler notifies this wait queue on receipt of an IRQ */
1426e41017aad9ed175ca51e4828eabc8c5cf5910beDean NelsonDECLARE_WAIT_QUEUE_HEAD(xpc_activate_IRQ_wq);
14389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
14489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonstatic unsigned long xpc_hb_check_timeout;
14533ba3c7724be79f7cdbfc611335572c056d9a05aDean Nelsonstatic struct timer_list xpc_hb_timer;
14689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
147e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson/* notification that the xpc_hb_checker thread has exited */
148f9e505a9a03df5acace6e758c8d12982635a1c64Jes Sorensenstatic DECLARE_COMPLETION(xpc_hb_checker_exited);
14989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
150e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson/* notification that the xpc_discovery thread has exited */
151f9e505a9a03df5acace6e758c8d12982635a1c64Jes Sorensenstatic DECLARE_COMPLETION(xpc_discovery_exited);
15289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
15389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonstatic void xpc_kthread_waitmsgs(struct xpc_partition *, struct xpc_channel *);
15489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
155a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelsonstatic int xpc_system_reboot(struct notifier_block *, unsigned long, void *);
156a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelsonstatic struct notifier_block xpc_reboot_notifier = {
157a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson	.notifier_call = xpc_system_reboot,
158a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson};
159a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson
160780d09e895032207a6b070a44d392a3c60574b70Dean Nelsonstatic int xpc_system_die(struct notifier_block *, unsigned long, void *);
161780d09e895032207a6b070a44d392a3c60574b70Dean Nelsonstatic struct notifier_block xpc_die_notifier = {
162780d09e895032207a6b070a44d392a3c60574b70Dean Nelson	.notifier_call = xpc_system_die,
163780d09e895032207a6b070a44d392a3c60574b70Dean Nelson};
164780d09e895032207a6b070a44d392a3c60574b70Dean Nelson
165a7665b0a380585fbd70a2275f3120c6086e0c92dRobin Holtstruct xpc_arch_operations xpc_arch_ops;
16694bd2708d4a95d7da5a1c7c28a063eccd127fb69Dean Nelson
167a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson/*
168a47d5dac9d8481766382f8cf1483dd581df38b99Dean Nelson * Timer function to enforce the timelimit on the partition disengage.
169a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson */
170a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelsonstatic void
171a47d5dac9d8481766382f8cf1483dd581df38b99Dean Nelsonxpc_timeout_partition_disengage(unsigned long data)
172a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson{
17335190506b1a18eda7df24b285fdcd94dec7800efDean Nelson	struct xpc_partition *part = (struct xpc_partition *)data;
174a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson
175a47d5dac9d8481766382f8cf1483dd581df38b99Dean Nelson	DBUG_ON(time_is_after_jiffies(part->disengage_timeout));
176a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson
17735190506b1a18eda7df24b285fdcd94dec7800efDean Nelson	(void)xpc_partition_disengaged(part);
178a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson
179a47d5dac9d8481766382f8cf1483dd581df38b99Dean Nelson	DBUG_ON(part->disengage_timeout != 0);
180a7665b0a380585fbd70a2275f3120c6086e0c92dRobin Holt	DBUG_ON(xpc_arch_ops.partition_engaged(XPC_PARTID(part)));
181a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson}
182a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson
18389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson/*
18489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * Timer to produce the heartbeat.  The timer structures function is
18589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * already set when this is initially called.  A tunable is used to
18689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * specify when the next timeout should occur.
18789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson */
18889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonstatic void
18989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonxpc_hb_beater(unsigned long dummy)
19089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson{
191a7665b0a380585fbd70a2275f3120c6086e0c92dRobin Holt	xpc_arch_ops.increment_heartbeat();
19289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
193aaa3cd694c0c4ae534e8aafdf4227e395c57d6bdDean Nelson	if (time_is_before_eq_jiffies(xpc_hb_check_timeout))
1946e41017aad9ed175ca51e4828eabc8c5cf5910beDean Nelson		wake_up_interruptible(&xpc_activate_IRQ_wq);
19589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
19689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	xpc_hb_timer.expires = jiffies + (xpc_hb_interval * HZ);
19789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	add_timer(&xpc_hb_timer);
19889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson}
19989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
20033ba3c7724be79f7cdbfc611335572c056d9a05aDean Nelsonstatic void
20133ba3c7724be79f7cdbfc611335572c056d9a05aDean Nelsonxpc_start_hb_beater(void)
20233ba3c7724be79f7cdbfc611335572c056d9a05aDean Nelson{
203a7665b0a380585fbd70a2275f3120c6086e0c92dRobin Holt	xpc_arch_ops.heartbeat_init();
20433ba3c7724be79f7cdbfc611335572c056d9a05aDean Nelson	init_timer(&xpc_hb_timer);
20533ba3c7724be79f7cdbfc611335572c056d9a05aDean Nelson	xpc_hb_timer.function = xpc_hb_beater;
20633ba3c7724be79f7cdbfc611335572c056d9a05aDean Nelson	xpc_hb_beater(0);
20733ba3c7724be79f7cdbfc611335572c056d9a05aDean Nelson}
20833ba3c7724be79f7cdbfc611335572c056d9a05aDean Nelson
20933ba3c7724be79f7cdbfc611335572c056d9a05aDean Nelsonstatic void
21033ba3c7724be79f7cdbfc611335572c056d9a05aDean Nelsonxpc_stop_hb_beater(void)
21133ba3c7724be79f7cdbfc611335572c056d9a05aDean Nelson{
21233ba3c7724be79f7cdbfc611335572c056d9a05aDean Nelson	del_timer_sync(&xpc_hb_timer);
213a7665b0a380585fbd70a2275f3120c6086e0c92dRobin Holt	xpc_arch_ops.heartbeat_exit();
21433ba3c7724be79f7cdbfc611335572c056d9a05aDean Nelson}
21533ba3c7724be79f7cdbfc611335572c056d9a05aDean Nelson
21689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson/*
21761deb86e98f51151b225f7563ee1cf2b50857d10Dean Nelson * At periodic intervals, scan through all active partitions and ensure
21861deb86e98f51151b225f7563ee1cf2b50857d10Dean Nelson * their heartbeat is still active.  If not, the partition is deactivated.
21961deb86e98f51151b225f7563ee1cf2b50857d10Dean Nelson */
22061deb86e98f51151b225f7563ee1cf2b50857d10Dean Nelsonstatic void
22161deb86e98f51151b225f7563ee1cf2b50857d10Dean Nelsonxpc_check_remote_hb(void)
22261deb86e98f51151b225f7563ee1cf2b50857d10Dean Nelson{
22361deb86e98f51151b225f7563ee1cf2b50857d10Dean Nelson	struct xpc_partition *part;
22461deb86e98f51151b225f7563ee1cf2b50857d10Dean Nelson	short partid;
22561deb86e98f51151b225f7563ee1cf2b50857d10Dean Nelson	enum xp_retval ret;
22661deb86e98f51151b225f7563ee1cf2b50857d10Dean Nelson
22761deb86e98f51151b225f7563ee1cf2b50857d10Dean Nelson	for (partid = 0; partid < xp_max_npartitions; partid++) {
22861deb86e98f51151b225f7563ee1cf2b50857d10Dean Nelson
22961deb86e98f51151b225f7563ee1cf2b50857d10Dean Nelson		if (xpc_exiting)
23061deb86e98f51151b225f7563ee1cf2b50857d10Dean Nelson			break;
23161deb86e98f51151b225f7563ee1cf2b50857d10Dean Nelson
23261deb86e98f51151b225f7563ee1cf2b50857d10Dean Nelson		if (partid == xp_partition_id)
23361deb86e98f51151b225f7563ee1cf2b50857d10Dean Nelson			continue;
23461deb86e98f51151b225f7563ee1cf2b50857d10Dean Nelson
23561deb86e98f51151b225f7563ee1cf2b50857d10Dean Nelson		part = &xpc_partitions[partid];
23661deb86e98f51151b225f7563ee1cf2b50857d10Dean Nelson
23783469b5525b4a35be40b17cb41d64118d84d9f80Dean Nelson		if (part->act_state == XPC_P_AS_INACTIVE ||
23883469b5525b4a35be40b17cb41d64118d84d9f80Dean Nelson		    part->act_state == XPC_P_AS_DEACTIVATING) {
23961deb86e98f51151b225f7563ee1cf2b50857d10Dean Nelson			continue;
24061deb86e98f51151b225f7563ee1cf2b50857d10Dean Nelson		}
24161deb86e98f51151b225f7563ee1cf2b50857d10Dean Nelson
242a7665b0a380585fbd70a2275f3120c6086e0c92dRobin Holt		ret = xpc_arch_ops.get_remote_heartbeat(part);
24361deb86e98f51151b225f7563ee1cf2b50857d10Dean Nelson		if (ret != xpSuccess)
24461deb86e98f51151b225f7563ee1cf2b50857d10Dean Nelson			XPC_DEACTIVATE_PARTITION(part, ret);
24561deb86e98f51151b225f7563ee1cf2b50857d10Dean Nelson	}
24661deb86e98f51151b225f7563ee1cf2b50857d10Dean Nelson}
24761deb86e98f51151b225f7563ee1cf2b50857d10Dean Nelson
24861deb86e98f51151b225f7563ee1cf2b50857d10Dean Nelson/*
24989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * This thread is responsible for nearly all of the partition
25089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * activation/deactivation.
25189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson */
25289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonstatic int
25389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonxpc_hb_checker(void *ignore)
25489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson{
25535190506b1a18eda7df24b285fdcd94dec7800efDean Nelson	int force_IRQ = 0;
25689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
25789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	/* this thread was marked active by xpc_hb_init() */
25889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
259f7df8ed164996cd2c6aca9674388be6ef78d8b37Rusty Russell	set_cpus_allowed_ptr(current, cpumask_of(XPC_HB_CHECK_CPU));
26089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
2614c013f5c7ea39cd62e02c80408560751b4e8c0deDean Nelson	/* set our heartbeating to other partitions into motion */
26289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	xpc_hb_check_timeout = jiffies + (xpc_hb_check_interval * HZ);
26333ba3c7724be79f7cdbfc611335572c056d9a05aDean Nelson	xpc_start_hb_beater();
26489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
2652c2b94f93f4732c3b9703ce62627e6187e7d6128Dean Nelson	while (!xpc_exiting) {
26689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
26789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		dev_dbg(xpc_part, "woke up with %d ticks rem; %d IRQs have "
26889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			"been received\n",
26935190506b1a18eda7df24b285fdcd94dec7800efDean Nelson			(int)(xpc_hb_check_timeout - jiffies),
2705b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson			xpc_activate_IRQ_rcvd);
27189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
27289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		/* checking of remote heartbeats is skewed by IRQ handling */
273aaa3cd694c0c4ae534e8aafdf4227e395c57d6bdDean Nelson		if (time_is_before_eq_jiffies(xpc_hb_check_timeout)) {
2745b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson			xpc_hb_check_timeout = jiffies +
2755b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson			    (xpc_hb_check_interval * HZ);
2765b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson
27789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			dev_dbg(xpc_part, "checking remote heartbeats\n");
27889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			xpc_check_remote_hb();
27989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
28089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			/*
2815b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson			 * On sn2 we need to periodically recheck to ensure no
2825b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson			 * IRQ/amo pairs have been missed.
28389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			 */
2845b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson			if (is_shub())
2855b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson				force_IRQ = 1;
28689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		}
28789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
288a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson		/* check for outstanding IRQs */
2895b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson		if (xpc_activate_IRQ_rcvd > 0 || force_IRQ != 0) {
29089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			force_IRQ = 0;
2915b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson			dev_dbg(xpc_part, "processing activate IRQs "
2925b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson				"received\n");
293a7665b0a380585fbd70a2275f3120c6086e0c92dRobin Holt			xpc_arch_ops.process_activate_IRQ_rcvd();
29489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		}
295a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson
296a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson		/* wait for IRQ or timeout */
2976e41017aad9ed175ca51e4828eabc8c5cf5910beDean Nelson		(void)wait_event_interruptible(xpc_activate_IRQ_wq,
2985b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson					       (time_is_before_eq_jiffies(
299aaa3cd694c0c4ae534e8aafdf4227e395c57d6bdDean Nelson						xpc_hb_check_timeout) ||
3005b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson						xpc_activate_IRQ_rcvd > 0 ||
3012c2b94f93f4732c3b9703ce62627e6187e7d6128Dean Nelson						xpc_exiting));
30289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	}
30389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
30433ba3c7724be79f7cdbfc611335572c056d9a05aDean Nelson	xpc_stop_hb_beater();
30533ba3c7724be79f7cdbfc611335572c056d9a05aDean Nelson
30689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	dev_dbg(xpc_part, "heartbeat checker is exiting\n");
30789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
308e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson	/* mark this thread as having exited */
309f9e505a9a03df5acace6e758c8d12982635a1c64Jes Sorensen	complete(&xpc_hb_checker_exited);
31089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	return 0;
31189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson}
31289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
31389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson/*
31489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * This thread will attempt to discover other partitions to activate
31589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * based on info provided by SAL. This new thread is short lived and
31689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * will exit once discovery is complete.
31789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson */
31889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonstatic int
31989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonxpc_initiate_discovery(void *ignore)
32089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson{
32189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	xpc_discovery();
32289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
32389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	dev_dbg(xpc_part, "discovery thread is exiting\n");
32489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
325e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson	/* mark this thread as having exited */
326f9e505a9a03df5acace6e758c8d12982635a1c64Jes Sorensen	complete(&xpc_discovery_exited);
32789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	return 0;
32889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson}
32989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
33089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson/*
33189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * The first kthread assigned to a newly activated partition is the one
332e17d416b1bc947df68499863f13b401fb42b48f6Dean Nelson * created by XPC HB with which it calls xpc_activating(). XPC hangs on to
33389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * that kthread until the partition is brought down, at which time that kthread
33489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * returns back to XPC HB. (The return of that kthread will signify to XPC HB
33589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * that XPC has dismantled all communication infrastructure for the associated
33689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * partition.) This kthread becomes the channel manager for that partition.
33789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *
33889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * Each active partition has a channel manager, who, besides connecting and
33989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * disconnecting channels, will ensure that each of the partition's connected
34089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * channels has the required number of assigned kthreads to get the work done.
34189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson */
34289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonstatic void
34389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonxpc_channel_mgr(struct xpc_partition *part)
34489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson{
34583469b5525b4a35be40b17cb41d64118d84d9f80Dean Nelson	while (part->act_state != XPC_P_AS_DEACTIVATING ||
34635190506b1a18eda7df24b285fdcd94dec7800efDean Nelson	       atomic_read(&part->nchannels_active) > 0 ||
34735190506b1a18eda7df24b285fdcd94dec7800efDean Nelson	       !xpc_partition_disengaged(part)) {
34889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
3497fb5e59d63deda89a8eefdbd5b3c8d622076afd4Dean Nelson		xpc_process_sent_chctl_flags(part);
35089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
35189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		/*
35289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		 * Wait until we've been requested to activate kthreads or
35389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		 * all of the channel's message queues have been torn down or
35489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		 * a signal is pending.
35589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		 *
35689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		 * The channel_mgr_requests is set to 1 after being awakened,
35789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		 * This is done to prevent the channel mgr from making one pass
35889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		 * through the loop for each request, since he will
35989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		 * be servicing all the requests in one pass. The reason it's
36089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		 * set to 1 instead of 0 is so that other kthreads will know
36189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		 * that the channel mgr is running and won't bother trying to
36289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		 * wake him up.
36389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		 */
36489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		atomic_dec(&part->channel_mgr_requests);
36535190506b1a18eda7df24b285fdcd94dec7800efDean Nelson		(void)wait_event_interruptible(part->channel_mgr_wq,
3662c2b94f93f4732c3b9703ce62627e6187e7d6128Dean Nelson				(atomic_read(&part->channel_mgr_requests) > 0 ||
3677fb5e59d63deda89a8eefdbd5b3c8d622076afd4Dean Nelson				 part->chctl.all_flags != 0 ||
36883469b5525b4a35be40b17cb41d64118d84d9f80Dean Nelson				 (part->act_state == XPC_P_AS_DEACTIVATING &&
3692c2b94f93f4732c3b9703ce62627e6187e7d6128Dean Nelson				 atomic_read(&part->nchannels_active) == 0 &&
3702c2b94f93f4732c3b9703ce62627e6187e7d6128Dean Nelson				 xpc_partition_disengaged(part))));
37189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		atomic_set(&part->channel_mgr_requests, 1);
37289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	}
37389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson}
37489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
37589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson/*
3765b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson * Guarantee that the kzalloc'd memory is cacheline aligned.
3775b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson */
3785b8669dfd110a62a74eea525a009342f73987ea0Dean Nelsonvoid *
3795b8669dfd110a62a74eea525a009342f73987ea0Dean Nelsonxpc_kzalloc_cacheline_aligned(size_t size, gfp_t flags, void **base)
3805b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson{
3815b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	/* see if kzalloc will give us cachline aligned memory by default */
3825b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	*base = kzalloc(size, flags);
3835b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	if (*base == NULL)
3845b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson		return NULL;
3855b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson
3865b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	if ((u64)*base == L1_CACHE_ALIGN((u64)*base))
3875b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson		return *base;
3885b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson
3895b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	kfree(*base);
3905b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson
3915b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	/* nope, we'll have to do it ourselves */
3925b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	*base = kzalloc(size + L1_CACHE_BYTES, flags);
3935b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	if (*base == NULL)
3945b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson		return NULL;
3955b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson
3965b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	return (void *)L1_CACHE_ALIGN((u64)*base);
3975b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson}
3985b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson
3995b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson/*
4005b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson * Setup the channel structures necessary to support XPartition Communication
4015b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson * between the specified remote partition and the local one.
4025b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson */
4035b8669dfd110a62a74eea525a009342f73987ea0Dean Nelsonstatic enum xp_retval
4045b8669dfd110a62a74eea525a009342f73987ea0Dean Nelsonxpc_setup_ch_structures(struct xpc_partition *part)
4055b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson{
4065b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	enum xp_retval ret;
4075b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	int ch_number;
4085b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	struct xpc_channel *ch;
4095b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	short partid = XPC_PARTID(part);
4105b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson
4115b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	/*
4125b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	 * Allocate all of the channel structures as a contiguous chunk of
4135b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	 * memory.
4145b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	 */
4155b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	DBUG_ON(part->channels != NULL);
4165b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	part->channels = kzalloc(sizeof(struct xpc_channel) * XPC_MAX_NCHANNELS,
4175b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson				 GFP_KERNEL);
4185b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	if (part->channels == NULL) {
4195b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson		dev_err(xpc_chan, "can't get memory for channels\n");
4205b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson		return xpNoMemory;
4215b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	}
4225b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson
4235b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	/* allocate the remote open and close args */
4245b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson
4255b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	part->remote_openclose_args =
4265b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	    xpc_kzalloc_cacheline_aligned(XPC_OPENCLOSE_ARGS_SIZE,
4275b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson					  GFP_KERNEL, &part->
4285b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson					  remote_openclose_args_base);
4295b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	if (part->remote_openclose_args == NULL) {
4305b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson		dev_err(xpc_chan, "can't get memory for remote connect args\n");
4315b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson		ret = xpNoMemory;
4325b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson		goto out_1;
4335b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	}
4345b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson
4355b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	part->chctl.all_flags = 0;
4365b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	spin_lock_init(&part->chctl_lock);
4375b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson
4385b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	atomic_set(&part->channel_mgr_requests, 1);
4395b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	init_waitqueue_head(&part->channel_mgr_wq);
4405b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson
4415b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	part->nchannels = XPC_MAX_NCHANNELS;
4425b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson
4435b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	atomic_set(&part->nchannels_active, 0);
4445b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	atomic_set(&part->nchannels_engaged, 0);
4455b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson
4465b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	for (ch_number = 0; ch_number < part->nchannels; ch_number++) {
4475b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson		ch = &part->channels[ch_number];
4485b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson
4495b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson		ch->partid = partid;
4505b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson		ch->number = ch_number;
4515b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson		ch->flags = XPC_C_DISCONNECTED;
4525b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson
4535b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson		atomic_set(&ch->kthreads_assigned, 0);
4545b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson		atomic_set(&ch->kthreads_idle, 0);
4555b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson		atomic_set(&ch->kthreads_active, 0);
4565b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson
4575b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson		atomic_set(&ch->references, 0);
4585b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson		atomic_set(&ch->n_to_notify, 0);
4595b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson
4605b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson		spin_lock_init(&ch->lock);
4615b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson		init_completion(&ch->wdisconnect_wait);
4625b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson
4635b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson		atomic_set(&ch->n_on_msg_allocate_wq, 0);
4645b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson		init_waitqueue_head(&ch->msg_allocate_wq);
4655b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson		init_waitqueue_head(&ch->idle_wq);
4665b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	}
4675b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson
468a7665b0a380585fbd70a2275f3120c6086e0c92dRobin Holt	ret = xpc_arch_ops.setup_ch_structures(part);
4695b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	if (ret != xpSuccess)
4705b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson		goto out_2;
4715b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson
4725b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	/*
4735b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	 * With the setting of the partition setup_state to XPC_P_SS_SETUP,
4745b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	 * we're declaring that this partition is ready to go.
4755b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	 */
4765b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	part->setup_state = XPC_P_SS_SETUP;
4775b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson
4785b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	return xpSuccess;
4795b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson
4805b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	/* setup of ch structures failed */
4815b8669dfd110a62a74eea525a009342f73987ea0Dean Nelsonout_2:
4825b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	kfree(part->remote_openclose_args_base);
4835b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	part->remote_openclose_args = NULL;
4845b8669dfd110a62a74eea525a009342f73987ea0Dean Nelsonout_1:
4855b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	kfree(part->channels);
4865b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	part->channels = NULL;
4875b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	return ret;
4885b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson}
4895b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson
4905b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson/*
4915b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson * Teardown the channel structures necessary to support XPartition Communication
4925b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson * between the specified remote partition and the local one.
4935b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson */
4945b8669dfd110a62a74eea525a009342f73987ea0Dean Nelsonstatic void
4955b8669dfd110a62a74eea525a009342f73987ea0Dean Nelsonxpc_teardown_ch_structures(struct xpc_partition *part)
4965b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson{
4975b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	DBUG_ON(atomic_read(&part->nchannels_engaged) != 0);
4985b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	DBUG_ON(atomic_read(&part->nchannels_active) != 0);
4995b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson
5005b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	/*
5015b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	 * Make this partition inaccessible to local processes by marking it
5025b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	 * as no longer setup. Then wait before proceeding with the teardown
5035b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	 * until all existing references cease.
5045b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	 */
5055b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	DBUG_ON(part->setup_state != XPC_P_SS_SETUP);
5065b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	part->setup_state = XPC_P_SS_WTEARDOWN;
5075b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson
5085b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	wait_event(part->teardown_wq, (atomic_read(&part->references) == 0));
5095b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson
5105b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	/* now we can begin tearing down the infrastructure */
5115b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson
512a7665b0a380585fbd70a2275f3120c6086e0c92dRobin Holt	xpc_arch_ops.teardown_ch_structures(part);
5135b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson
5145b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	kfree(part->remote_openclose_args_base);
5155b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	part->remote_openclose_args = NULL;
5165b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	kfree(part->channels);
5175b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	part->channels = NULL;
5185b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson
5195b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	part->setup_state = XPC_P_SS_TORNDOWN;
5205b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson}
5215b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson
5225b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson/*
52389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * When XPC HB determines that a partition has come up, it will create a new
52489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * kthread and that kthread will call this function to attempt to set up the
52589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * basic infrastructure used for Cross Partition Communication with the newly
52689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * upped partition.
52789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *
52889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * The kthread that was created by XPC HB and which setup the XPC
529e17d416b1bc947df68499863f13b401fb42b48f6Dean Nelson * infrastructure will remain assigned to the partition becoming the channel
530e17d416b1bc947df68499863f13b401fb42b48f6Dean Nelson * manager for that partition until the partition is deactivating, at which
531e17d416b1bc947df68499863f13b401fb42b48f6Dean Nelson * time the kthread will teardown the XPC infrastructure and then exit.
53289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson */
53389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonstatic int
53489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonxpc_activating(void *__partid)
53589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson{
53664d032ba434ad41586460811148f01511e5612f9Dean Nelson	short partid = (u64)__partid;
53789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	struct xpc_partition *part = &xpc_partitions[partid];
53889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	unsigned long irq_flags;
53989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
540bc63d387e4f5dbbe4ea0c5ade862c38073fd7fa3Dean Nelson	DBUG_ON(partid < 0 || partid >= xp_max_npartitions);
54189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
54289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	spin_lock_irqsave(&part->act_lock, irq_flags);
54389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
54483469b5525b4a35be40b17cb41d64118d84d9f80Dean Nelson	if (part->act_state == XPC_P_AS_DEACTIVATING) {
54583469b5525b4a35be40b17cb41d64118d84d9f80Dean Nelson		part->act_state = XPC_P_AS_INACTIVE;
54689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		spin_unlock_irqrestore(&part->act_lock, irq_flags);
54789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		part->remote_rp_pa = 0;
54889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		return 0;
54989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	}
55089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
55189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	/* indicate the thread is activating */
55283469b5525b4a35be40b17cb41d64118d84d9f80Dean Nelson	DBUG_ON(part->act_state != XPC_P_AS_ACTIVATION_REQ);
55383469b5525b4a35be40b17cb41d64118d84d9f80Dean Nelson	part->act_state = XPC_P_AS_ACTIVATING;
55489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
55589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	XPC_SET_REASON(part, 0, 0);
55689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	spin_unlock_irqrestore(&part->act_lock, irq_flags);
55789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
558e17d416b1bc947df68499863f13b401fb42b48f6Dean Nelson	dev_dbg(xpc_part, "activating partition %d\n", partid);
55989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
560a7665b0a380585fbd70a2275f3120c6086e0c92dRobin Holt	xpc_arch_ops.allow_hb(partid);
56189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
5625b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	if (xpc_setup_ch_structures(part) == xpSuccess) {
563e17d416b1bc947df68499863f13b401fb42b48f6Dean Nelson		(void)xpc_part_ref(part);	/* this will always succeed */
564e17d416b1bc947df68499863f13b401fb42b48f6Dean Nelson
565a7665b0a380585fbd70a2275f3120c6086e0c92dRobin Holt		if (xpc_arch_ops.make_first_contact(part) == xpSuccess) {
566e17d416b1bc947df68499863f13b401fb42b48f6Dean Nelson			xpc_mark_partition_active(part);
567e17d416b1bc947df68499863f13b401fb42b48f6Dean Nelson			xpc_channel_mgr(part);
568e17d416b1bc947df68499863f13b401fb42b48f6Dean Nelson			/* won't return until partition is deactivating */
569e17d416b1bc947df68499863f13b401fb42b48f6Dean Nelson		}
570e17d416b1bc947df68499863f13b401fb42b48f6Dean Nelson
571e17d416b1bc947df68499863f13b401fb42b48f6Dean Nelson		xpc_part_deref(part);
5725b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson		xpc_teardown_ch_structures(part);
573e17d416b1bc947df68499863f13b401fb42b48f6Dean Nelson	}
57489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
575a7665b0a380585fbd70a2275f3120c6086e0c92dRobin Holt	xpc_arch_ops.disallow_hb(partid);
57689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	xpc_mark_partition_inactive(part);
57789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
57865c17b801e03e40acdca0cd34e8eb1b8a347b539Dean Nelson	if (part->reason == xpReactivating) {
57989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		/* interrupting ourselves results in activating partition */
580a7665b0a380585fbd70a2275f3120c6086e0c92dRobin Holt		xpc_arch_ops.request_partition_reactivation(part);
58189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	}
58289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
58389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	return 0;
58489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson}
58589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
58689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonvoid
58789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonxpc_activate_partition(struct xpc_partition *part)
58889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson{
58964d032ba434ad41586460811148f01511e5612f9Dean Nelson	short partid = XPC_PARTID(part);
59089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	unsigned long irq_flags;
5912c2b94f93f4732c3b9703ce62627e6187e7d6128Dean Nelson	struct task_struct *kthread;
59289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
59389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	spin_lock_irqsave(&part->act_lock, irq_flags);
59489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
59583469b5525b4a35be40b17cb41d64118d84d9f80Dean Nelson	DBUG_ON(part->act_state != XPC_P_AS_INACTIVE);
59689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
59783469b5525b4a35be40b17cb41d64118d84d9f80Dean Nelson	part->act_state = XPC_P_AS_ACTIVATION_REQ;
59865c17b801e03e40acdca0cd34e8eb1b8a347b539Dean Nelson	XPC_SET_REASON(part, xpCloneKThread, __LINE__);
59989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
60089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	spin_unlock_irqrestore(&part->act_lock, irq_flags);
6017c6c66362941df847957766ad133ff5fde67579cRobin Holt
6022c2b94f93f4732c3b9703ce62627e6187e7d6128Dean Nelson	kthread = kthread_run(xpc_activating, (void *)((u64)partid), "xpc%02d",
6032c2b94f93f4732c3b9703ce62627e6187e7d6128Dean Nelson			      partid);
6042c2b94f93f4732c3b9703ce62627e6187e7d6128Dean Nelson	if (IS_ERR(kthread)) {
6057c6c66362941df847957766ad133ff5fde67579cRobin Holt		spin_lock_irqsave(&part->act_lock, irq_flags);
60683469b5525b4a35be40b17cb41d64118d84d9f80Dean Nelson		part->act_state = XPC_P_AS_INACTIVE;
60765c17b801e03e40acdca0cd34e8eb1b8a347b539Dean Nelson		XPC_SET_REASON(part, xpCloneKThreadFailed, __LINE__);
6087c6c66362941df847957766ad133ff5fde67579cRobin Holt		spin_unlock_irqrestore(&part->act_lock, irq_flags);
6097c6c66362941df847957766ad133ff5fde67579cRobin Holt	}
61089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson}
61189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
61289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonvoid
61389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonxpc_activate_kthreads(struct xpc_channel *ch, int needed)
61489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson{
61589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	int idle = atomic_read(&ch->kthreads_idle);
61689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	int assigned = atomic_read(&ch->kthreads_assigned);
61789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	int wakeup;
61889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
61989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	DBUG_ON(needed <= 0);
62089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
62189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	if (idle > 0) {
62289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		wakeup = (needed > idle) ? idle : needed;
62389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		needed -= wakeup;
62489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
62589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		dev_dbg(xpc_chan, "wakeup %d idle kthreads, partid=%d, "
62689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			"channel=%d\n", wakeup, ch->partid, ch->number);
62789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
62889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		/* only wakeup the requested number of kthreads */
62989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		wake_up_nr(&ch->idle_wq, wakeup);
63089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	}
63189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
6322c2b94f93f4732c3b9703ce62627e6187e7d6128Dean Nelson	if (needed <= 0)
63389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		return;
63489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
63589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	if (needed + assigned > ch->kthreads_assigned_limit) {
63689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		needed = ch->kthreads_assigned_limit - assigned;
6372c2b94f93f4732c3b9703ce62627e6187e7d6128Dean Nelson		if (needed <= 0)
63889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			return;
63989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	}
64089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
64189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	dev_dbg(xpc_chan, "create %d new kthreads, partid=%d, channel=%d\n",
64289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		needed, ch->partid, ch->number);
64389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
644a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson	xpc_create_kthreads(ch, needed, 0);
64589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson}
64689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
64789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson/*
64889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * This function is where XPC's kthreads wait for messages to deliver.
64989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson */
65089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonstatic void
65189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonxpc_kthread_waitmsgs(struct xpc_partition *part, struct xpc_channel *ch)
65289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson{
653a7665b0a380585fbd70a2275f3120c6086e0c92dRobin Holt	int (*n_of_deliverable_payloads) (struct xpc_channel *) =
654a7665b0a380585fbd70a2275f3120c6086e0c92dRobin Holt		xpc_arch_ops.n_of_deliverable_payloads;
655a7665b0a380585fbd70a2275f3120c6086e0c92dRobin Holt
65689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	do {
65789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		/* deliver messages to their intended recipients */
65889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
659a7665b0a380585fbd70a2275f3120c6086e0c92dRobin Holt		while (n_of_deliverable_payloads(ch) > 0 &&
6602c2b94f93f4732c3b9703ce62627e6187e7d6128Dean Nelson		       !(ch->flags & XPC_C_DISCONNECTING)) {
661bd3e64c1759e4930315ebf022611468ee9621486Dean Nelson			xpc_deliver_payload(ch);
66289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		}
66389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
66489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		if (atomic_inc_return(&ch->kthreads_idle) >
66535190506b1a18eda7df24b285fdcd94dec7800efDean Nelson		    ch->kthreads_idle_limit) {
66689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			/* too many idle kthreads on this channel */
66789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			atomic_dec(&ch->kthreads_idle);
66889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			break;
66989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		}
67089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
67189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		dev_dbg(xpc_chan, "idle kthread calling "
67289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			"wait_event_interruptible_exclusive()\n");
67389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
67435190506b1a18eda7df24b285fdcd94dec7800efDean Nelson		(void)wait_event_interruptible_exclusive(ch->idle_wq,
675a7665b0a380585fbd70a2275f3120c6086e0c92dRobin Holt				(n_of_deliverable_payloads(ch) > 0 ||
6762c2b94f93f4732c3b9703ce62627e6187e7d6128Dean Nelson				 (ch->flags & XPC_C_DISCONNECTING)));
67789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
67889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		atomic_dec(&ch->kthreads_idle);
67989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
6802c2b94f93f4732c3b9703ce62627e6187e7d6128Dean Nelson	} while (!(ch->flags & XPC_C_DISCONNECTING));
68189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson}
68289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
68389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonstatic int
6842c2b94f93f4732c3b9703ce62627e6187e7d6128Dean Nelsonxpc_kthread_start(void *args)
68589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson{
68664d032ba434ad41586460811148f01511e5612f9Dean Nelson	short partid = XPC_UNPACK_ARG1(args);
68789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	u16 ch_number = XPC_UNPACK_ARG2(args);
68889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	struct xpc_partition *part = &xpc_partitions[partid];
68989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	struct xpc_channel *ch;
69089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	int n_needed;
691e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson	unsigned long irq_flags;
692a7665b0a380585fbd70a2275f3120c6086e0c92dRobin Holt	int (*n_of_deliverable_payloads) (struct xpc_channel *) =
693a7665b0a380585fbd70a2275f3120c6086e0c92dRobin Holt		xpc_arch_ops.n_of_deliverable_payloads;
69489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
69589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	dev_dbg(xpc_chan, "kthread starting, partid=%d, channel=%d\n",
69689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		partid, ch_number);
69789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
69889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	ch = &part->channels[ch_number];
69989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
70089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	if (!(ch->flags & XPC_C_DISCONNECTING)) {
70189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
70289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		/* let registerer know that connection has been established */
70389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
704e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson		spin_lock_irqsave(&ch->lock, irq_flags);
7054c2cd96696ae0896ce4bcf725b9f0eaffafeb640Dean Nelson		if (!(ch->flags & XPC_C_CONNECTEDCALLOUT)) {
7064c2cd96696ae0896ce4bcf725b9f0eaffafeb640Dean Nelson			ch->flags |= XPC_C_CONNECTEDCALLOUT;
707e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson			spin_unlock_irqrestore(&ch->lock, irq_flags);
708e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson
70989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			xpc_connected_callout(ch);
71089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
7114c2cd96696ae0896ce4bcf725b9f0eaffafeb640Dean Nelson			spin_lock_irqsave(&ch->lock, irq_flags);
7124c2cd96696ae0896ce4bcf725b9f0eaffafeb640Dean Nelson			ch->flags |= XPC_C_CONNECTEDCALLOUT_MADE;
7134c2cd96696ae0896ce4bcf725b9f0eaffafeb640Dean Nelson			spin_unlock_irqrestore(&ch->lock, irq_flags);
7144c2cd96696ae0896ce4bcf725b9f0eaffafeb640Dean Nelson
71589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			/*
71689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			 * It is possible that while the callout was being
71789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			 * made that the remote partition sent some messages.
71889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			 * If that is the case, we may need to activate
71989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			 * additional kthreads to help deliver them. We only
72089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			 * need one less than total #of messages to deliver.
72189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			 */
722a7665b0a380585fbd70a2275f3120c6086e0c92dRobin Holt			n_needed = n_of_deliverable_payloads(ch) - 1;
7232c2b94f93f4732c3b9703ce62627e6187e7d6128Dean Nelson			if (n_needed > 0 && !(ch->flags & XPC_C_DISCONNECTING))
72489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson				xpc_activate_kthreads(ch, n_needed);
7252c2b94f93f4732c3b9703ce62627e6187e7d6128Dean Nelson
726e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson		} else {
727e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson			spin_unlock_irqrestore(&ch->lock, irq_flags);
72889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		}
72989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
73089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		xpc_kthread_waitmsgs(part, ch);
73189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	}
73289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
733a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson	/* let registerer know that connection is disconnecting */
734e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson
735a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson	spin_lock_irqsave(&ch->lock, irq_flags);
736a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson	if ((ch->flags & XPC_C_CONNECTEDCALLOUT_MADE) &&
73735190506b1a18eda7df24b285fdcd94dec7800efDean Nelson	    !(ch->flags & XPC_C_DISCONNECTINGCALLOUT)) {
738a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson		ch->flags |= XPC_C_DISCONNECTINGCALLOUT;
7394c2cd96696ae0896ce4bcf725b9f0eaffafeb640Dean Nelson		spin_unlock_irqrestore(&ch->lock, irq_flags);
740a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson
74165c17b801e03e40acdca0cd34e8eb1b8a347b539Dean Nelson		xpc_disconnect_callout(ch, xpDisconnecting);
742a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson
743a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson		spin_lock_irqsave(&ch->lock, irq_flags);
744a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson		ch->flags |= XPC_C_DISCONNECTINGCALLOUT_MADE;
745a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson	}
746a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson	spin_unlock_irqrestore(&ch->lock, irq_flags);
747a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson
748a47d5dac9d8481766382f8cf1483dd581df38b99Dean Nelson	if (atomic_dec_return(&ch->kthreads_assigned) == 0 &&
749a47d5dac9d8481766382f8cf1483dd581df38b99Dean Nelson	    atomic_dec_return(&part->nchannels_engaged) == 0) {
750a7665b0a380585fbd70a2275f3120c6086e0c92dRobin Holt		xpc_arch_ops.indicate_partition_disengaged(part);
75189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	}
75289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
75389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	xpc_msgqueue_deref(ch);
75489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
75589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	dev_dbg(xpc_chan, "kthread exiting, partid=%d, channel=%d\n",
75689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		partid, ch_number);
75789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
75889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	xpc_part_deref(part);
75989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	return 0;
76089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson}
76189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
76289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson/*
76389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * For each partition that XPC has established communications with, there is
76489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * a minimum of one kernel thread assigned to perform any operation that
76589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * may potentially sleep or block (basically the callouts to the asynchronous
76689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * functions registered via xpc_connect()).
76789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *
76889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * Additional kthreads are created and destroyed by XPC as the workload
76989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * demands.
77089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson *
77189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * A kthread is assigned to one of the active channels that exists for a given
77289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson * partition.
77389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson */
77489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonvoid
775a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelsonxpc_create_kthreads(struct xpc_channel *ch, int needed,
77635190506b1a18eda7df24b285fdcd94dec7800efDean Nelson		    int ignore_disconnecting)
77789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson{
77889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	unsigned long irq_flags;
77989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	u64 args = XPC_PACK_ARGS(ch->partid, ch->number);
780a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson	struct xpc_partition *part = &xpc_partitions[ch->partid];
7812c2b94f93f4732c3b9703ce62627e6187e7d6128Dean Nelson	struct task_struct *kthread;
782a7665b0a380585fbd70a2275f3120c6086e0c92dRobin Holt	void (*indicate_partition_disengaged) (struct xpc_partition *) =
783a7665b0a380585fbd70a2275f3120c6086e0c92dRobin Holt		xpc_arch_ops.indicate_partition_disengaged;
78489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
78589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	while (needed-- > 0) {
786e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson
787e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson		/*
788e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson		 * The following is done on behalf of the newly created
789e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson		 * kthread. That kthread is responsible for doing the
790e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson		 * counterpart to the following before it exits.
791e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson		 */
792a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson		if (ignore_disconnecting) {
793a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson			if (!atomic_inc_not_zero(&ch->kthreads_assigned)) {
794a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson				/* kthreads assigned had gone to zero */
795a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson				BUG_ON(!(ch->flags &
79635190506b1a18eda7df24b285fdcd94dec7800efDean Nelson					 XPC_C_DISCONNECTINGCALLOUT_MADE));
797a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson				break;
798a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson			}
799a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson
800a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson		} else if (ch->flags & XPC_C_DISCONNECTING) {
801a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson			break;
802a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson
803a47d5dac9d8481766382f8cf1483dd581df38b99Dean Nelson		} else if (atomic_inc_return(&ch->kthreads_assigned) == 1 &&
804a47d5dac9d8481766382f8cf1483dd581df38b99Dean Nelson			   atomic_inc_return(&part->nchannels_engaged) == 1) {
805a7665b0a380585fbd70a2275f3120c6086e0c92dRobin Holt			xpc_arch_ops.indicate_partition_engaged(part);
806a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson		}
80735190506b1a18eda7df24b285fdcd94dec7800efDean Nelson		(void)xpc_part_ref(part);
808e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson		xpc_msgqueue_ref(ch);
809e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson
8102c2b94f93f4732c3b9703ce62627e6187e7d6128Dean Nelson		kthread = kthread_run(xpc_kthread_start, (void *)args,
8112c2b94f93f4732c3b9703ce62627e6187e7d6128Dean Nelson				      "xpc%02dc%d", ch->partid, ch->number);
8122c2b94f93f4732c3b9703ce62627e6187e7d6128Dean Nelson		if (IS_ERR(kthread)) {
81389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			/* the fork failed */
814a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson
815a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson			/*
816a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson			 * NOTE: if (ignore_disconnecting &&
817a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson			 * !(ch->flags & XPC_C_DISCONNECTINGCALLOUT)) is true,
818a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson			 * then we'll deadlock if all other kthreads assigned
819a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson			 * to this channel are blocked in the channel's
820a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson			 * registerer, because the only thing that will unblock
82165c17b801e03e40acdca0cd34e8eb1b8a347b539Dean Nelson			 * them is the xpDisconnecting callout that this
8222c2b94f93f4732c3b9703ce62627e6187e7d6128Dean Nelson			 * failed kthread_run() would have made.
823a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson			 */
824a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120Dean Nelson
825e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson			if (atomic_dec_return(&ch->kthreads_assigned) == 0 &&
826e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson			    atomic_dec_return(&part->nchannels_engaged) == 0) {
827a7665b0a380585fbd70a2275f3120c6086e0c92dRobin Holt				indicate_partition_disengaged(part);
828e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson			}
829e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson			xpc_msgqueue_deref(ch);
830e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson			xpc_part_deref(part);
83189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
83289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			if (atomic_read(&ch->kthreads_assigned) <
83335190506b1a18eda7df24b285fdcd94dec7800efDean Nelson			    ch->kthreads_idle_limit) {
83489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson				/*
83589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson				 * Flag this as an error only if we have an
83689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson				 * insufficient #of kthreads for the channel
83789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson				 * to function.
83889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson				 */
83989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson				spin_lock_irqsave(&ch->lock, irq_flags);
84065c17b801e03e40acdca0cd34e8eb1b8a347b539Dean Nelson				XPC_DISCONNECT_CHANNEL(ch, xpLackOfResources,
84135190506b1a18eda7df24b285fdcd94dec7800efDean Nelson						       &irq_flags);
84289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson				spin_unlock_irqrestore(&ch->lock, irq_flags);
84389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			}
84489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			break;
84589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		}
84689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	}
84789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson}
84889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
84989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonvoid
85089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonxpc_disconnect_wait(int ch_number)
85189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson{
852a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson	unsigned long irq_flags;
85364d032ba434ad41586460811148f01511e5612f9Dean Nelson	short partid;
85489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	struct xpc_partition *part;
85589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	struct xpc_channel *ch;
856e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson	int wakeup_channel_mgr;
85789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
85889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	/* now wait for all callouts to the caller's function to cease */
859bc63d387e4f5dbbe4ea0c5ade862c38073fd7fa3Dean Nelson	for (partid = 0; partid < xp_max_npartitions; partid++) {
86089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		part = &xpc_partitions[partid];
86189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
8622c2b94f93f4732c3b9703ce62627e6187e7d6128Dean Nelson		if (!xpc_part_ref(part))
863e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson			continue;
86489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
865e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson		ch = &part->channels[ch_number];
86689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
867e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson		if (!(ch->flags & XPC_C_WDISCONNECT)) {
86889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			xpc_part_deref(part);
869e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson			continue;
87089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		}
871e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson
872f9e505a9a03df5acace6e758c8d12982635a1c64Jes Sorensen		wait_for_completion(&ch->wdisconnect_wait);
873e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson
874e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson		spin_lock_irqsave(&ch->lock, irq_flags);
875e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson		DBUG_ON(!(ch->flags & XPC_C_DISCONNECTED));
876e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson		wakeup_channel_mgr = 0;
877e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson
8787fb5e59d63deda89a8eefdbd5b3c8d622076afd4Dean Nelson		if (ch->delayed_chctl_flags) {
87983469b5525b4a35be40b17cb41d64118d84d9f80Dean Nelson			if (part->act_state != XPC_P_AS_DEACTIVATING) {
8807fb5e59d63deda89a8eefdbd5b3c8d622076afd4Dean Nelson				spin_lock(&part->chctl_lock);
8817fb5e59d63deda89a8eefdbd5b3c8d622076afd4Dean Nelson				part->chctl.flags[ch->number] |=
8827fb5e59d63deda89a8eefdbd5b3c8d622076afd4Dean Nelson				    ch->delayed_chctl_flags;
8837fb5e59d63deda89a8eefdbd5b3c8d622076afd4Dean Nelson				spin_unlock(&part->chctl_lock);
884e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson				wakeup_channel_mgr = 1;
885e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson			}
8867fb5e59d63deda89a8eefdbd5b3c8d622076afd4Dean Nelson			ch->delayed_chctl_flags = 0;
88789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		}
888e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson
889e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson		ch->flags &= ~XPC_C_WDISCONNECT;
890e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson		spin_unlock_irqrestore(&ch->lock, irq_flags);
891e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson
8922c2b94f93f4732c3b9703ce62627e6187e7d6128Dean Nelson		if (wakeup_channel_mgr)
893e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson			xpc_wakeup_channel_mgr(part);
894e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson
895e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson		xpc_part_deref(part);
89689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	}
89789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson}
89889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
8995b8669dfd110a62a74eea525a009342f73987ea0Dean Nelsonstatic int
9005b8669dfd110a62a74eea525a009342f73987ea0Dean Nelsonxpc_setup_partitions(void)
9015b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson{
9025b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	short partid;
9035b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	struct xpc_partition *part;
9045b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson
9055b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	xpc_partitions = kzalloc(sizeof(struct xpc_partition) *
9065b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson				 xp_max_npartitions, GFP_KERNEL);
9075b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	if (xpc_partitions == NULL) {
9085b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson		dev_err(xpc_part, "can't get memory for partition structure\n");
9095b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson		return -ENOMEM;
9105b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	}
9115b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson
9125b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	/*
9135b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	 * The first few fields of each entry of xpc_partitions[] need to
9145b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	 * be initialized now so that calls to xpc_connect() and
9155b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	 * xpc_disconnect() can be made prior to the activation of any remote
9165b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	 * partition. NOTE THAT NONE OF THE OTHER FIELDS BELONGING TO THESE
9175b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	 * ENTRIES ARE MEANINGFUL UNTIL AFTER AN ENTRY'S CORRESPONDING
9185b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	 * PARTITION HAS BEEN ACTIVATED.
9195b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	 */
9205b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	for (partid = 0; partid < xp_max_npartitions; partid++) {
9215b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson		part = &xpc_partitions[partid];
9225b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson
9235b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson		DBUG_ON((u64)part != L1_CACHE_ALIGN((u64)part));
9245b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson
9255b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson		part->activate_IRQ_rcvd = 0;
9265b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson		spin_lock_init(&part->act_lock);
9275b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson		part->act_state = XPC_P_AS_INACTIVE;
9285b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson		XPC_SET_REASON(part, 0, 0);
9295b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson
9305b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson		init_timer(&part->disengage_timer);
9315b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson		part->disengage_timer.function =
9325b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson		    xpc_timeout_partition_disengage;
9335b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson		part->disengage_timer.data = (unsigned long)part;
9345b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson
9355b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson		part->setup_state = XPC_P_SS_UNSET;
9365b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson		init_waitqueue_head(&part->teardown_wq);
9375b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson		atomic_set(&part->references, 0);
9385b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	}
9395b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson
940a7665b0a380585fbd70a2275f3120c6086e0c92dRobin Holt	return xpc_arch_ops.setup_partitions();
9415b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson}
9425b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson
9435b8669dfd110a62a74eea525a009342f73987ea0Dean Nelsonstatic void
9445b8669dfd110a62a74eea525a009342f73987ea0Dean Nelsonxpc_teardown_partitions(void)
9455b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson{
946a7665b0a380585fbd70a2275f3120c6086e0c92dRobin Holt	xpc_arch_ops.teardown_partitions();
9475b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	kfree(xpc_partitions);
9485b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson}
9495b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson
95089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonstatic void
95165c17b801e03e40acdca0cd34e8eb1b8a347b539Dean Nelsonxpc_do_exit(enum xp_retval reason)
95289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson{
95364d032ba434ad41586460811148f01511e5612f9Dean Nelson	short partid;
9541ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson	int active_part_count, printed_waiting_msg = 0;
95589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	struct xpc_partition *part;
956a47d5dac9d8481766382f8cf1483dd581df38b99Dean Nelson	unsigned long printmsg_time, disengage_timeout = 0;
95789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
958a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson	/* a 'rmmod XPC' and a 'reboot' cannot both end up here together */
959a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson	DBUG_ON(xpc_exiting == 1);
96089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
96189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	/*
962a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson	 * Let the heartbeat checker thread and the discovery thread
963a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson	 * (if one is running) know that they should exit. Also wake up
964a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson	 * the heartbeat checker thread in case it's sleeping.
96589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 */
96689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	xpc_exiting = 1;
9676e41017aad9ed175ca51e4828eabc8c5cf5910beDean Nelson	wake_up_interruptible(&xpc_activate_IRQ_wq);
96889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
969e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson	/* wait for the discovery thread to exit */
970f9e505a9a03df5acace6e758c8d12982635a1c64Jes Sorensen	wait_for_completion(&xpc_discovery_exited);
97189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
972e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson	/* wait for the heartbeat checker thread to exit */
973f9e505a9a03df5acace6e758c8d12982635a1c64Jes Sorensen	wait_for_completion(&xpc_hb_checker_exited);
97489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
975a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson	/* sleep for a 1/3 of a second or so */
97635190506b1a18eda7df24b285fdcd94dec7800efDean Nelson	(void)msleep_interruptible(300);
97789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
97889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	/* wait for all partitions to become inactive */
97989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
980a47d5dac9d8481766382f8cf1483dd581df38b99Dean Nelson	printmsg_time = jiffies + (XPC_DEACTIVATE_PRINTMSG_INTERVAL * HZ);
981a47d5dac9d8481766382f8cf1483dd581df38b99Dean Nelson	xpc_disengage_timedout = 0;
982a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson
98389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	do {
98489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		active_part_count = 0;
98589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
986bc63d387e4f5dbbe4ea0c5ade862c38073fd7fa3Dean Nelson		for (partid = 0; partid < xp_max_npartitions; partid++) {
98789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			part = &xpc_partitions[partid];
98889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
989a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson			if (xpc_partition_disengaged(part) &&
99083469b5525b4a35be40b17cb41d64118d84d9f80Dean Nelson			    part->act_state == XPC_P_AS_INACTIVE) {
991a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson				continue;
99289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson			}
993a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson
994a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson			active_part_count++;
995a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson
996a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson			XPC_DEACTIVATE_PARTITION(part, reason);
99789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
998a47d5dac9d8481766382f8cf1483dd581df38b99Dean Nelson			if (part->disengage_timeout > disengage_timeout)
999a47d5dac9d8481766382f8cf1483dd581df38b99Dean Nelson				disengage_timeout = part->disengage_timeout;
1000a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson		}
100189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
1002a7665b0a380585fbd70a2275f3120c6086e0c92dRobin Holt		if (xpc_arch_ops.any_partition_engaged()) {
1003aaa3cd694c0c4ae534e8aafdf4227e395c57d6bdDean Nelson			if (time_is_before_jiffies(printmsg_time)) {
10041ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson				dev_info(xpc_part, "waiting for remote "
1005a47d5dac9d8481766382f8cf1483dd581df38b99Dean Nelson					 "partitions to deactivate, timeout in "
1006a47d5dac9d8481766382f8cf1483dd581df38b99Dean Nelson					 "%ld seconds\n", (disengage_timeout -
1007a47d5dac9d8481766382f8cf1483dd581df38b99Dean Nelson					 jiffies) / HZ);
10081ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson				printmsg_time = jiffies +
1009a47d5dac9d8481766382f8cf1483dd581df38b99Dean Nelson				    (XPC_DEACTIVATE_PRINTMSG_INTERVAL * HZ);
10101ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson				printed_waiting_msg = 1;
10111ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson			}
10121ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson
10131ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson		} else if (active_part_count > 0) {
10141ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson			if (printed_waiting_msg) {
10151ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson				dev_info(xpc_part, "waiting for local partition"
1016a47d5dac9d8481766382f8cf1483dd581df38b99Dean Nelson					 " to deactivate\n");
10171ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson				printed_waiting_msg = 0;
10181ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson			}
10191ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson
10201ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson		} else {
1021a47d5dac9d8481766382f8cf1483dd581df38b99Dean Nelson			if (!xpc_disengage_timedout) {
10221ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson				dev_info(xpc_part, "all partitions have "
1023a47d5dac9d8481766382f8cf1483dd581df38b99Dean Nelson					 "deactivated\n");
10241ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson			}
10251ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson			break;
102689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		}
102789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
1028a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson		/* sleep for a 1/3 of a second or so */
102935190506b1a18eda7df24b285fdcd94dec7800efDean Nelson		(void)msleep_interruptible(300);
1030a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson
1031a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson	} while (1);
1032a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson
1033a7665b0a380585fbd70a2275f3120c6086e0c92dRobin Holt	DBUG_ON(xpc_arch_ops.any_partition_engaged());
1034a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson
10355b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	xpc_teardown_rsvd_page();
1036a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson
103765c17b801e03e40acdca0cd34e8eb1b8a347b539Dean Nelson	if (reason == xpUnloading) {
103835190506b1a18eda7df24b285fdcd94dec7800efDean Nelson		(void)unregister_die_notifier(&xpc_die_notifier);
1039bc63d387e4f5dbbe4ea0c5ade862c38073fd7fa3Dean Nelson		(void)unregister_reboot_notifier(&xpc_reboot_notifier);
10400752c670d83362609c7f3f59ffa0e180709c60c2Dean Nelson	}
1041780d09e895032207a6b070a44d392a3c60574b70Dean Nelson
104289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	/* clear the interface to XPC's functions */
104389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	xpc_clear_interface();
104489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
10452c2b94f93f4732c3b9703ce62627e6187e7d6128Dean Nelson	if (xpc_sysctl)
104689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		unregister_sysctl_table(xpc_sysctl);
10477682a4c624e0011b5f3e8dd3021dc54961260d97Dean Nelson
10485b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	xpc_teardown_partitions();
10496e41017aad9ed175ca51e4828eabc8c5cf5910beDean Nelson
10506e41017aad9ed175ca51e4828eabc8c5cf5910beDean Nelson	if (is_shub())
10516e41017aad9ed175ca51e4828eabc8c5cf5910beDean Nelson		xpc_exit_sn2();
1052b7f7b07479de2d91443b81938db1e1940c56b13cDean Nelson	else if (is_uv())
10536e41017aad9ed175ca51e4828eabc8c5cf5910beDean Nelson		xpc_exit_uv();
105489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson}
105589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
1056a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson/*
1057d6ad033a88b42420ddb6c62c95e42f88d862b246Dean Nelson * This function is called when the system is being rebooted.
1058d6ad033a88b42420ddb6c62c95e42f88d862b246Dean Nelson */
1059d6ad033a88b42420ddb6c62c95e42f88d862b246Dean Nelsonstatic int
1060d6ad033a88b42420ddb6c62c95e42f88d862b246Dean Nelsonxpc_system_reboot(struct notifier_block *nb, unsigned long event, void *unused)
1061d6ad033a88b42420ddb6c62c95e42f88d862b246Dean Nelson{
106265c17b801e03e40acdca0cd34e8eb1b8a347b539Dean Nelson	enum xp_retval reason;
1063d6ad033a88b42420ddb6c62c95e42f88d862b246Dean Nelson
1064d6ad033a88b42420ddb6c62c95e42f88d862b246Dean Nelson	switch (event) {
1065d6ad033a88b42420ddb6c62c95e42f88d862b246Dean Nelson	case SYS_RESTART:
106665c17b801e03e40acdca0cd34e8eb1b8a347b539Dean Nelson		reason = xpSystemReboot;
1067d6ad033a88b42420ddb6c62c95e42f88d862b246Dean Nelson		break;
1068d6ad033a88b42420ddb6c62c95e42f88d862b246Dean Nelson	case SYS_HALT:
106965c17b801e03e40acdca0cd34e8eb1b8a347b539Dean Nelson		reason = xpSystemHalt;
1070d6ad033a88b42420ddb6c62c95e42f88d862b246Dean Nelson		break;
1071d6ad033a88b42420ddb6c62c95e42f88d862b246Dean Nelson	case SYS_POWER_OFF:
107265c17b801e03e40acdca0cd34e8eb1b8a347b539Dean Nelson		reason = xpSystemPoweroff;
1073d6ad033a88b42420ddb6c62c95e42f88d862b246Dean Nelson		break;
1074d6ad033a88b42420ddb6c62c95e42f88d862b246Dean Nelson	default:
107565c17b801e03e40acdca0cd34e8eb1b8a347b539Dean Nelson		reason = xpSystemGoingDown;
1076d6ad033a88b42420ddb6c62c95e42f88d862b246Dean Nelson	}
1077d6ad033a88b42420ddb6c62c95e42f88d862b246Dean Nelson
1078d6ad033a88b42420ddb6c62c95e42f88d862b246Dean Nelson	xpc_do_exit(reason);
1079d6ad033a88b42420ddb6c62c95e42f88d862b246Dean Nelson	return NOTIFY_DONE;
1080d6ad033a88b42420ddb6c62c95e42f88d862b246Dean Nelson}
1081d6ad033a88b42420ddb6c62c95e42f88d862b246Dean Nelson
1082d6ad033a88b42420ddb6c62c95e42f88d862b246Dean Nelson/*
1083a47d5dac9d8481766382f8cf1483dd581df38b99Dean Nelson * Notify other partitions to deactivate from us by first disengaging from all
1084a47d5dac9d8481766382f8cf1483dd581df38b99Dean Nelson * references to our memory.
1085780d09e895032207a6b070a44d392a3c60574b70Dean Nelson */
1086780d09e895032207a6b070a44d392a3c60574b70Dean Nelsonstatic void
1087a47d5dac9d8481766382f8cf1483dd581df38b99Dean Nelsonxpc_die_deactivate(void)
1088780d09e895032207a6b070a44d392a3c60574b70Dean Nelson{
1089780d09e895032207a6b070a44d392a3c60574b70Dean Nelson	struct xpc_partition *part;
109064d032ba434ad41586460811148f01511e5612f9Dean Nelson	short partid;
1091a47d5dac9d8481766382f8cf1483dd581df38b99Dean Nelson	int any_engaged;
1092261f3b4979db88d29fc86aad9f76fbc0c2c6d21aDean Nelson	long keep_waiting;
1093261f3b4979db88d29fc86aad9f76fbc0c2c6d21aDean Nelson	long wait_to_print;
1094780d09e895032207a6b070a44d392a3c60574b70Dean Nelson
1095780d09e895032207a6b070a44d392a3c60574b70Dean Nelson	/* keep xpc_hb_checker thread from doing anything (just in case) */
1096780d09e895032207a6b070a44d392a3c60574b70Dean Nelson	xpc_exiting = 1;
1097780d09e895032207a6b070a44d392a3c60574b70Dean Nelson
1098a7665b0a380585fbd70a2275f3120c6086e0c92dRobin Holt	xpc_arch_ops.disallow_all_hbs();   /*indicate we're deactivated */
1099780d09e895032207a6b070a44d392a3c60574b70Dean Nelson
1100bc63d387e4f5dbbe4ea0c5ade862c38073fd7fa3Dean Nelson	for (partid = 0; partid < xp_max_npartitions; partid++) {
1101780d09e895032207a6b070a44d392a3c60574b70Dean Nelson		part = &xpc_partitions[partid];
1102780d09e895032207a6b070a44d392a3c60574b70Dean Nelson
1103a7665b0a380585fbd70a2275f3120c6086e0c92dRobin Holt		if (xpc_arch_ops.partition_engaged(partid) ||
110483469b5525b4a35be40b17cb41d64118d84d9f80Dean Nelson		    part->act_state != XPC_P_AS_INACTIVE) {
1105a7665b0a380585fbd70a2275f3120c6086e0c92dRobin Holt			xpc_arch_ops.request_partition_deactivation(part);
1106a7665b0a380585fbd70a2275f3120c6086e0c92dRobin Holt			xpc_arch_ops.indicate_partition_disengaged(part);
1107780d09e895032207a6b070a44d392a3c60574b70Dean Nelson		}
1108780d09e895032207a6b070a44d392a3c60574b70Dean Nelson	}
1109780d09e895032207a6b070a44d392a3c60574b70Dean Nelson
1110a47d5dac9d8481766382f8cf1483dd581df38b99Dean Nelson	/*
1111a47d5dac9d8481766382f8cf1483dd581df38b99Dean Nelson	 * Though we requested that all other partitions deactivate from us,
1112261f3b4979db88d29fc86aad9f76fbc0c2c6d21aDean Nelson	 * we only wait until they've all disengaged or we've reached the
1113261f3b4979db88d29fc86aad9f76fbc0c2c6d21aDean Nelson	 * defined timelimit.
1114261f3b4979db88d29fc86aad9f76fbc0c2c6d21aDean Nelson	 *
1115261f3b4979db88d29fc86aad9f76fbc0c2c6d21aDean Nelson	 * Given that one iteration through the following while-loop takes
1116261f3b4979db88d29fc86aad9f76fbc0c2c6d21aDean Nelson	 * approximately 200 microseconds, calculate the #of loops to take
1117261f3b4979db88d29fc86aad9f76fbc0c2c6d21aDean Nelson	 * before bailing and the #of loops before printing a waiting message.
1118a47d5dac9d8481766382f8cf1483dd581df38b99Dean Nelson	 */
1119261f3b4979db88d29fc86aad9f76fbc0c2c6d21aDean Nelson	keep_waiting = xpc_disengage_timelimit * 1000 * 5;
1120261f3b4979db88d29fc86aad9f76fbc0c2c6d21aDean Nelson	wait_to_print = XPC_DEACTIVATE_PRINTMSG_INTERVAL * 1000 * 5;
1121780d09e895032207a6b070a44d392a3c60574b70Dean Nelson
11221ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson	while (1) {
1123a7665b0a380585fbd70a2275f3120c6086e0c92dRobin Holt		any_engaged = xpc_arch_ops.any_partition_engaged();
1124a47d5dac9d8481766382f8cf1483dd581df38b99Dean Nelson		if (!any_engaged) {
1125a47d5dac9d8481766382f8cf1483dd581df38b99Dean Nelson			dev_info(xpc_part, "all partitions have deactivated\n");
11261ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson			break;
11271ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson		}
1128780d09e895032207a6b070a44d392a3c60574b70Dean Nelson
1129261f3b4979db88d29fc86aad9f76fbc0c2c6d21aDean Nelson		if (!keep_waiting--) {
1130bc63d387e4f5dbbe4ea0c5ade862c38073fd7fa3Dean Nelson			for (partid = 0; partid < xp_max_npartitions;
1131bc63d387e4f5dbbe4ea0c5ade862c38073fd7fa3Dean Nelson			     partid++) {
1132a7665b0a380585fbd70a2275f3120c6086e0c92dRobin Holt				if (xpc_arch_ops.partition_engaged(partid)) {
1133a47d5dac9d8481766382f8cf1483dd581df38b99Dean Nelson					dev_info(xpc_part, "deactivate from "
113435190506b1a18eda7df24b285fdcd94dec7800efDean Nelson						 "remote partition %d timed "
113535190506b1a18eda7df24b285fdcd94dec7800efDean Nelson						 "out\n", partid);
11361ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson				}
11371ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson			}
11381ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson			break;
11391ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson		}
11401ecaded80f94f2779160529aef7d6f37a22c2f60Dean Nelson
1141261f3b4979db88d29fc86aad9f76fbc0c2c6d21aDean Nelson		if (!wait_to_print--) {
1142780d09e895032207a6b070a44d392a3c60574b70Dean Nelson			dev_info(xpc_part, "waiting for remote partitions to "
1143a47d5dac9d8481766382f8cf1483dd581df38b99Dean Nelson				 "deactivate, timeout in %ld seconds\n",
1144261f3b4979db88d29fc86aad9f76fbc0c2c6d21aDean Nelson				 keep_waiting / (1000 * 5));
1145261f3b4979db88d29fc86aad9f76fbc0c2c6d21aDean Nelson			wait_to_print = XPC_DEACTIVATE_PRINTMSG_INTERVAL *
1146261f3b4979db88d29fc86aad9f76fbc0c2c6d21aDean Nelson			    1000 * 5;
1147780d09e895032207a6b070a44d392a3c60574b70Dean Nelson		}
1148261f3b4979db88d29fc86aad9f76fbc0c2c6d21aDean Nelson
1149261f3b4979db88d29fc86aad9f76fbc0c2c6d21aDean Nelson		udelay(200);
1150780d09e895032207a6b070a44d392a3c60574b70Dean Nelson	}
1151780d09e895032207a6b070a44d392a3c60574b70Dean Nelson}
1152780d09e895032207a6b070a44d392a3c60574b70Dean Nelson
1153780d09e895032207a6b070a44d392a3c60574b70Dean Nelson/*
11541f4674b2d5f63bac4c393ac4de1d6c1b6b72c09cDean Nelson * This function is called when the system is being restarted or halted due
11551f4674b2d5f63bac4c393ac4de1d6c1b6b72c09cDean Nelson * to some sort of system failure. If this is the case we need to notify the
11561f4674b2d5f63bac4c393ac4de1d6c1b6b72c09cDean Nelson * other partitions to disengage from all references to our memory.
11571f4674b2d5f63bac4c393ac4de1d6c1b6b72c09cDean Nelson * This function can also be called when our heartbeater could be offlined
11581f4674b2d5f63bac4c393ac4de1d6c1b6b72c09cDean Nelson * for a time. In this case we need to notify other partitions to not worry
11591f4674b2d5f63bac4c393ac4de1d6c1b6b72c09cDean Nelson * about the lack of a heartbeat.
1160780d09e895032207a6b070a44d392a3c60574b70Dean Nelson */
1161780d09e895032207a6b070a44d392a3c60574b70Dean Nelsonstatic int
1162780d09e895032207a6b070a44d392a3c60574b70Dean Nelsonxpc_system_die(struct notifier_block *nb, unsigned long event, void *unused)
1163780d09e895032207a6b070a44d392a3c60574b70Dean Nelson{
1164261f3b4979db88d29fc86aad9f76fbc0c2c6d21aDean Nelson#ifdef CONFIG_IA64		/* !!! temporary kludge */
1165780d09e895032207a6b070a44d392a3c60574b70Dean Nelson	switch (event) {
1166780d09e895032207a6b070a44d392a3c60574b70Dean Nelson	case DIE_MACHINE_RESTART:
1167780d09e895032207a6b070a44d392a3c60574b70Dean Nelson	case DIE_MACHINE_HALT:
1168a47d5dac9d8481766382f8cf1483dd581df38b99Dean Nelson		xpc_die_deactivate();
1169780d09e895032207a6b070a44d392a3c60574b70Dean Nelson		break;
11701f4674b2d5f63bac4c393ac4de1d6c1b6b72c09cDean Nelson
11711f4674b2d5f63bac4c393ac4de1d6c1b6b72c09cDean Nelson	case DIE_KDEBUG_ENTER:
11721f4674b2d5f63bac4c393ac4de1d6c1b6b72c09cDean Nelson		/* Should lack of heartbeat be ignored by other partitions? */
11732c2b94f93f4732c3b9703ce62627e6187e7d6128Dean Nelson		if (!xpc_kdebug_ignore)
11741f4674b2d5f63bac4c393ac4de1d6c1b6b72c09cDean Nelson			break;
11752c2b94f93f4732c3b9703ce62627e6187e7d6128Dean Nelson
11761f4674b2d5f63bac4c393ac4de1d6c1b6b72c09cDean Nelson		/* fall through */
1177780d09e895032207a6b070a44d392a3c60574b70Dean Nelson	case DIE_MCA_MONARCH_ENTER:
1178780d09e895032207a6b070a44d392a3c60574b70Dean Nelson	case DIE_INIT_MONARCH_ENTER:
1179a7665b0a380585fbd70a2275f3120c6086e0c92dRobin Holt		xpc_arch_ops.offline_heartbeat();
1180780d09e895032207a6b070a44d392a3c60574b70Dean Nelson		break;
11811f4674b2d5f63bac4c393ac4de1d6c1b6b72c09cDean Nelson
11821f4674b2d5f63bac4c393ac4de1d6c1b6b72c09cDean Nelson	case DIE_KDEBUG_LEAVE:
11831f4674b2d5f63bac4c393ac4de1d6c1b6b72c09cDean Nelson		/* Is lack of heartbeat being ignored by other partitions? */
11842c2b94f93f4732c3b9703ce62627e6187e7d6128Dean Nelson		if (!xpc_kdebug_ignore)
11851f4674b2d5f63bac4c393ac4de1d6c1b6b72c09cDean Nelson			break;
11862c2b94f93f4732c3b9703ce62627e6187e7d6128Dean Nelson
11871f4674b2d5f63bac4c393ac4de1d6c1b6b72c09cDean Nelson		/* fall through */
1188780d09e895032207a6b070a44d392a3c60574b70Dean Nelson	case DIE_MCA_MONARCH_LEAVE:
1189780d09e895032207a6b070a44d392a3c60574b70Dean Nelson	case DIE_INIT_MONARCH_LEAVE:
1190a7665b0a380585fbd70a2275f3120c6086e0c92dRobin Holt		xpc_arch_ops.online_heartbeat();
1191780d09e895032207a6b070a44d392a3c60574b70Dean Nelson		break;
1192780d09e895032207a6b070a44d392a3c60574b70Dean Nelson	}
1193261f3b4979db88d29fc86aad9f76fbc0c2c6d21aDean Nelson#else
1194261f3b4979db88d29fc86aad9f76fbc0c2c6d21aDean Nelson	xpc_die_deactivate();
1195261f3b4979db88d29fc86aad9f76fbc0c2c6d21aDean Nelson#endif
1196780d09e895032207a6b070a44d392a3c60574b70Dean Nelson
1197780d09e895032207a6b070a44d392a3c60574b70Dean Nelson	return NOTIFY_DONE;
1198780d09e895032207a6b070a44d392a3c60574b70Dean Nelson}
1199780d09e895032207a6b070a44d392a3c60574b70Dean Nelson
120089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonint __init
120189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonxpc_init(void)
120289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson{
120389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	int ret;
12042c2b94f93f4732c3b9703ce62627e6187e7d6128Dean Nelson	struct task_struct *kthread;
1205ee6665e3b6e1283c30ae240732af1345bc02154eDean Nelson
1206bb0dc43eeeea6a3ace7fae42e583a9be176eb1f9Kay Sievers	dev_set_name(xpc_part, "part");
1207bb0dc43eeeea6a3ace7fae42e583a9be176eb1f9Kay Sievers	dev_set_name(xpc_chan, "chan");
120889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
120994bd2708d4a95d7da5a1c7c28a063eccd127fb69Dean Nelson	if (is_shub()) {
121094bd2708d4a95d7da5a1c7c28a063eccd127fb69Dean Nelson		/*
121194bd2708d4a95d7da5a1c7c28a063eccd127fb69Dean Nelson		 * The ia64-sn2 architecture supports at most 64 partitions.
1212c39838ce21ca8e05857ed7f4be5d289011561905Dean Nelson		 * And the inability to unregister remote amos restricts us
121394bd2708d4a95d7da5a1c7c28a063eccd127fb69Dean Nelson		 * further to only support exactly 64 partitions on this
121494bd2708d4a95d7da5a1c7c28a063eccd127fb69Dean Nelson		 * architecture, no less.
121594bd2708d4a95d7da5a1c7c28a063eccd127fb69Dean Nelson		 */
12165b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson		if (xp_max_npartitions != 64) {
12175b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson			dev_err(xpc_part, "max #of partitions not set to 64\n");
12185b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson			ret = -EINVAL;
12195b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson		} else {
12205b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson			ret = xpc_init_sn2();
12215b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson		}
122294bd2708d4a95d7da5a1c7c28a063eccd127fb69Dean Nelson
122394bd2708d4a95d7da5a1c7c28a063eccd127fb69Dean Nelson	} else if (is_uv()) {
12245b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson		ret = xpc_init_uv();
122594bd2708d4a95d7da5a1c7c28a063eccd127fb69Dean Nelson
122694bd2708d4a95d7da5a1c7c28a063eccd127fb69Dean Nelson	} else {
12275b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson		ret = -ENODEV;
122894bd2708d4a95d7da5a1c7c28a063eccd127fb69Dean Nelson	}
1229408865ce4829376120489ac8011b72125453dcffDean Nelson
12305b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	if (ret != 0)
12315b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson		return ret;
12325b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson
12335b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	ret = xpc_setup_partitions();
12345b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	if (ret != 0) {
1235bc63d387e4f5dbbe4ea0c5ade862c38073fd7fa3Dean Nelson		dev_err(xpc_part, "can't get memory for partition structure\n");
1236ee6665e3b6e1283c30ae240732af1345bc02154eDean Nelson		goto out_1;
1237bc63d387e4f5dbbe4ea0c5ade862c38073fd7fa3Dean Nelson	}
123889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
1239bc63d387e4f5dbbe4ea0c5ade862c38073fd7fa3Dean Nelson	xpc_sysctl = register_sysctl_table(xpc_sys_dir);
1240bc63d387e4f5dbbe4ea0c5ade862c38073fd7fa3Dean Nelson
124189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	/*
124289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 * Fill the partition reserved page with the information needed by
124389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 * other partitions to discover we are alive and establish initial
124489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 * communications.
124589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 */
12465b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	ret = xpc_setup_rsvd_page();
12475b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	if (ret != 0) {
1248bc63d387e4f5dbbe4ea0c5ade862c38073fd7fa3Dean Nelson		dev_err(xpc_part, "can't setup our reserved page\n");
1249ee6665e3b6e1283c30ae240732af1345bc02154eDean Nelson		goto out_2;
125089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	}
125189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
1252a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson	/* add ourselves to the reboot_notifier_list */
1253a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson	ret = register_reboot_notifier(&xpc_reboot_notifier);
12542c2b94f93f4732c3b9703ce62627e6187e7d6128Dean Nelson	if (ret != 0)
1255a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson		dev_warn(xpc_part, "can't register reboot notifier\n");
1256a607c38971fd078865fa9bef39e6c1d4435680c8Dean Nelson
12571eeb66a1bb973534dc3d064920a5ca683823372eChristoph Hellwig	/* add ourselves to the die_notifier list */
1258780d09e895032207a6b070a44d392a3c60574b70Dean Nelson	ret = register_die_notifier(&xpc_die_notifier);
12592c2b94f93f4732c3b9703ce62627e6187e7d6128Dean Nelson	if (ret != 0)
1260780d09e895032207a6b070a44d392a3c60574b70Dean Nelson		dev_warn(xpc_part, "can't register die notifier\n");
1261780d09e895032207a6b070a44d392a3c60574b70Dean Nelson
126289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	/*
126389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 * The real work-horse behind xpc.  This processes incoming
126489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 * interrupts and monitors remote heartbeats.
126589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 */
12662c2b94f93f4732c3b9703ce62627e6187e7d6128Dean Nelson	kthread = kthread_run(xpc_hb_checker, NULL, XPC_HB_CHECK_THREAD_NAME);
12672c2b94f93f4732c3b9703ce62627e6187e7d6128Dean Nelson	if (IS_ERR(kthread)) {
126889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		dev_err(xpc_part, "failed while forking hb check thread\n");
1269bc63d387e4f5dbbe4ea0c5ade862c38073fd7fa3Dean Nelson		ret = -EBUSY;
1270ee6665e3b6e1283c30ae240732af1345bc02154eDean Nelson		goto out_3;
127189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	}
127289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
127389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	/*
127489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 * Startup a thread that will attempt to discover other partitions to
127589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 * activate based on info provided by SAL. This new thread is short
127689eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 * lived and will exit once discovery is complete.
127789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	 */
12782c2b94f93f4732c3b9703ce62627e6187e7d6128Dean Nelson	kthread = kthread_run(xpc_initiate_discovery, NULL,
12792c2b94f93f4732c3b9703ce62627e6187e7d6128Dean Nelson			      XPC_DISCOVERY_THREAD_NAME);
12802c2b94f93f4732c3b9703ce62627e6187e7d6128Dean Nelson	if (IS_ERR(kthread)) {
128189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		dev_err(xpc_part, "failed while forking discovery thread\n");
128289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
128389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		/* mark this new thread as a non-starter */
1284f9e505a9a03df5acace6e758c8d12982635a1c64Jes Sorensen		complete(&xpc_discovery_exited);
128589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
128665c17b801e03e40acdca0cd34e8eb1b8a347b539Dean Nelson		xpc_do_exit(xpUnloading);
128789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson		return -EBUSY;
128889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	}
128989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
129089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	/* set the interface to point at XPC's functions */
129189eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	xpc_set_interface(xpc_initiate_connect, xpc_initiate_disconnect,
129297bf1aa1e1bb18de9bb1987c6eb9ad751bf08aabDean Nelson			  xpc_initiate_send, xpc_initiate_send_notify,
129397bf1aa1e1bb18de9bb1987c6eb9ad751bf08aabDean Nelson			  xpc_initiate_received, xpc_initiate_partid_to_nasids);
129489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
129589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson	return 0;
1296bc63d387e4f5dbbe4ea0c5ade862c38073fd7fa3Dean Nelson
1297bc63d387e4f5dbbe4ea0c5ade862c38073fd7fa3Dean Nelson	/* initialization was not successful */
1298ee6665e3b6e1283c30ae240732af1345bc02154eDean Nelsonout_3:
12995b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	xpc_teardown_rsvd_page();
130094bd2708d4a95d7da5a1c7c28a063eccd127fb69Dean Nelson
1301bc63d387e4f5dbbe4ea0c5ade862c38073fd7fa3Dean Nelson	(void)unregister_die_notifier(&xpc_die_notifier);
1302bc63d387e4f5dbbe4ea0c5ade862c38073fd7fa3Dean Nelson	(void)unregister_reboot_notifier(&xpc_reboot_notifier);
1303ee6665e3b6e1283c30ae240732af1345bc02154eDean Nelsonout_2:
1304bc63d387e4f5dbbe4ea0c5ade862c38073fd7fa3Dean Nelson	if (xpc_sysctl)
1305bc63d387e4f5dbbe4ea0c5ade862c38073fd7fa3Dean Nelson		unregister_sysctl_table(xpc_sysctl);
13065b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson
13075b8669dfd110a62a74eea525a009342f73987ea0Dean Nelson	xpc_teardown_partitions();
13086e41017aad9ed175ca51e4828eabc8c5cf5910beDean Nelsonout_1:
13096e41017aad9ed175ca51e4828eabc8c5cf5910beDean Nelson	if (is_shub())
13106e41017aad9ed175ca51e4828eabc8c5cf5910beDean Nelson		xpc_exit_sn2();
1311b7f7b07479de2d91443b81938db1e1940c56b13cDean Nelson	else if (is_uv())
13126e41017aad9ed175ca51e4828eabc8c5cf5910beDean Nelson		xpc_exit_uv();
1313bc63d387e4f5dbbe4ea0c5ade862c38073fd7fa3Dean Nelson	return ret;
131489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson}
131589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
131635190506b1a18eda7df24b285fdcd94dec7800efDean Nelsonmodule_init(xpc_init);
131789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
131889eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonvoid __exit
131989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonxpc_exit(void)
132089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson{
132165c17b801e03e40acdca0cd34e8eb1b8a347b539Dean Nelson	xpc_do_exit(xpUnloading);
132289eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson}
132389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
132435190506b1a18eda7df24b285fdcd94dec7800efDean Nelsonmodule_exit(xpc_exit);
132589eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
132689eb8eb927e324366c3ac0458998aaf9953fc5cdDean NelsonMODULE_AUTHOR("Silicon Graphics, Inc.");
132789eb8eb927e324366c3ac0458998aaf9953fc5cdDean NelsonMODULE_DESCRIPTION("Cross Partition Communication (XPC) support");
132889eb8eb927e324366c3ac0458998aaf9953fc5cdDean NelsonMODULE_LICENSE("GPL");
132989eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
133089eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonmodule_param(xpc_hb_interval, int, 0);
133189eb8eb927e324366c3ac0458998aaf9953fc5cdDean NelsonMODULE_PARM_DESC(xpc_hb_interval, "Number of seconds between "
133235190506b1a18eda7df24b285fdcd94dec7800efDean Nelson		 "heartbeat increments.");
133389eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
133489eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelsonmodule_param(xpc_hb_check_interval, int, 0);
133589eb8eb927e324366c3ac0458998aaf9953fc5cdDean NelsonMODULE_PARM_DESC(xpc_hb_check_interval, "Number of seconds between "
133635190506b1a18eda7df24b285fdcd94dec7800efDean Nelson		 "heartbeat checks.");
133789eb8eb927e324366c3ac0458998aaf9953fc5cdDean Nelson
1338a47d5dac9d8481766382f8cf1483dd581df38b99Dean Nelsonmodule_param(xpc_disengage_timelimit, int, 0);
1339a47d5dac9d8481766382f8cf1483dd581df38b99Dean NelsonMODULE_PARM_DESC(xpc_disengage_timelimit, "Number of seconds to wait "
1340a47d5dac9d8481766382f8cf1483dd581df38b99Dean Nelson		 "for disengage to complete.");
1341e54af724c1ae3530c95135157776c9be65cdb747Dean Nelson
13421f4674b2d5f63bac4c393ac4de1d6c1b6b72c09cDean Nelsonmodule_param(xpc_kdebug_ignore, int, 0);
13431f4674b2d5f63bac4c393ac4de1d6c1b6b72c09cDean NelsonMODULE_PARM_DESC(xpc_kdebug_ignore, "Should lack of heartbeat be ignored by "
134435190506b1a18eda7df24b285fdcd94dec7800efDean Nelson		 "other partitions when dropping into kdebug.");
1345