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