blob: f7478cc3572dd62f7f3fa1b372ee60eca9bad13c [file] [log] [blame]
Dean Nelson89eb8eb2005-03-23 19:50:00 -07001/*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
4 * for more details.
5 *
Dean Nelson45d9ca42008-04-22 14:46:56 -05006 * Copyright (c) 2004-2008 Silicon Graphics, Inc. All Rights Reserved.
Dean Nelson89eb8eb2005-03-23 19:50:00 -07007 */
8
Dean Nelson89eb8eb2005-03-23 19:50:00 -07009/*
10 * Cross Partition Communication (XPC) support - standard version.
11 *
12 * XPC provides a message passing capability that crosses partition
13 * boundaries. This module is made up of two parts:
14 *
15 * partition This part detects the presence/absence of other
16 * partitions. It provides a heartbeat and monitors
17 * the heartbeats of other partitions.
18 *
19 * channel This part manages the channels and sends/receives
20 * messages across them to/from other partitions.
21 *
22 * There are a couple of additional functions residing in XP, which
23 * provide an interface to XPC for its users.
24 *
25 *
26 * Caveats:
27 *
Dean Nelson7fb5e592008-07-29 22:34:10 -070028 * . Currently on sn2, we have no way to determine which nasid an IRQ
Dean Nelsonc39838c2008-07-29 22:34:11 -070029 * came from. Thus, xpc_send_IRQ_sn2() does a remote amo write
30 * followed by an IPI. The amo indicates where data is to be pulled
31 * from, so after the IPI arrives, the remote partition checks the amo
32 * word. The IPI can actually arrive before the amo however, so other
33 * code must periodically check for this case. Also, remote amo
Dean Nelson7fb5e592008-07-29 22:34:10 -070034 * operations do not reliably time out. Thus we do a remote PIO read
35 * solely to know whether the remote partition is down and whether we
36 * should stop sending IPIs to it. This remote PIO read operation is
37 * set up in a special nofault region so SAL knows to ignore (and
Dean Nelsonc39838c2008-07-29 22:34:11 -070038 * cleanup) any errors due to the remote amo write, PIO read, and/or
Dean Nelson7fb5e592008-07-29 22:34:10 -070039 * PIO write operations.
Dean Nelson89eb8eb2005-03-23 19:50:00 -070040 *
41 * If/when new hardware solves this IPI problem, we should abandon
42 * the current approach.
43 *
44 */
45
Dean Nelson89eb8eb2005-03-23 19:50:00 -070046#include <linux/module.h>
Dean Nelson261f3b42008-07-29 22:34:16 -070047#include <linux/sysctl.h>
48#include <linux/device.h>
Nishanth Aravamudan69913922005-07-08 17:10:00 -070049#include <linux/delay.h>
Dean Nelsona607c382005-09-01 14:01:37 -050050#include <linux/reboot.h>
Christoph Hellwig1eeb66a2007-05-08 00:27:03 -070051#include <linux/kdebug.h>
Dean Nelson2c2b94f2008-04-22 14:50:17 -050052#include <linux/kthread.h>
Dean Nelson45d9ca42008-04-22 14:46:56 -050053#include "xpc.h"
Dean Nelson89eb8eb2005-03-23 19:50:00 -070054
Dean Nelson89eb8eb2005-03-23 19:50:00 -070055/* define two XPC debug device structures to be used with dev_dbg() et al */
56
57struct device_driver xpc_dbg_name = {
58 .name = "xpc"
59};
60
61struct device xpc_part_dbg_subname = {
62 .bus_id = {0}, /* set to "part" at xpc_init() time */
63 .driver = &xpc_dbg_name
64};
65
66struct device xpc_chan_dbg_subname = {
67 .bus_id = {0}, /* set to "chan" at xpc_init() time */
68 .driver = &xpc_dbg_name
69};
70
71struct device *xpc_part = &xpc_part_dbg_subname;
72struct device *xpc_chan = &xpc_chan_dbg_subname;
73
Dean Nelson1f4674b2006-01-10 11:08:00 -060074static int xpc_kdebug_ignore;
75
Dean Nelson89eb8eb2005-03-23 19:50:00 -070076/* systune related variables for /proc/sys directories */
77
Dean Nelsona607c382005-09-01 14:01:37 -050078static int xpc_hb_interval = XPC_HB_DEFAULT_INTERVAL;
79static int xpc_hb_min_interval = 1;
80static int xpc_hb_max_interval = 10;
Dean Nelson89eb8eb2005-03-23 19:50:00 -070081
Dean Nelsona607c382005-09-01 14:01:37 -050082static int xpc_hb_check_interval = XPC_HB_CHECK_DEFAULT_INTERVAL;
83static int xpc_hb_check_min_interval = 10;
84static int xpc_hb_check_max_interval = 120;
Dean Nelson89eb8eb2005-03-23 19:50:00 -070085
Dean Nelsona47d5da2008-07-29 22:34:09 -070086int xpc_disengage_timelimit = XPC_DISENGAGE_DEFAULT_TIMELIMIT;
87static int xpc_disengage_min_timelimit; /* = 0 */
88static int xpc_disengage_max_timelimit = 120;
Dean Nelson89eb8eb2005-03-23 19:50:00 -070089
90static ctl_table xpc_sys_xpc_hb_dir[] = {
91 {
Dean Nelson35190502008-04-22 14:48:55 -050092 .ctl_name = CTL_UNNUMBERED,
93 .procname = "hb_interval",
94 .data = &xpc_hb_interval,
95 .maxlen = sizeof(int),
96 .mode = 0644,
97 .proc_handler = &proc_dointvec_minmax,
98 .strategy = &sysctl_intvec,
99 .extra1 = &xpc_hb_min_interval,
100 .extra2 = &xpc_hb_max_interval},
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700101 {
Dean Nelson35190502008-04-22 14:48:55 -0500102 .ctl_name = CTL_UNNUMBERED,
103 .procname = "hb_check_interval",
104 .data = &xpc_hb_check_interval,
105 .maxlen = sizeof(int),
106 .mode = 0644,
107 .proc_handler = &proc_dointvec_minmax,
108 .strategy = &sysctl_intvec,
109 .extra1 = &xpc_hb_check_min_interval,
110 .extra2 = &xpc_hb_check_max_interval},
Eric W. Biederman68cbf072007-02-14 00:33:41 -0800111 {}
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700112};
113static ctl_table xpc_sys_xpc_dir[] = {
114 {
Dean Nelson35190502008-04-22 14:48:55 -0500115 .ctl_name = CTL_UNNUMBERED,
116 .procname = "hb",
117 .mode = 0555,
118 .child = xpc_sys_xpc_hb_dir},
Dean Nelsone54af722005-10-25 14:07:43 -0500119 {
Dean Nelson35190502008-04-22 14:48:55 -0500120 .ctl_name = CTL_UNNUMBERED,
Dean Nelsona47d5da2008-07-29 22:34:09 -0700121 .procname = "disengage_timelimit",
122 .data = &xpc_disengage_timelimit,
Dean Nelson35190502008-04-22 14:48:55 -0500123 .maxlen = sizeof(int),
124 .mode = 0644,
125 .proc_handler = &proc_dointvec_minmax,
126 .strategy = &sysctl_intvec,
Dean Nelsona47d5da2008-07-29 22:34:09 -0700127 .extra1 = &xpc_disengage_min_timelimit,
128 .extra2 = &xpc_disengage_max_timelimit},
Eric W. Biederman68cbf072007-02-14 00:33:41 -0800129 {}
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700130};
131static ctl_table xpc_sys_dir[] = {
132 {
Dean Nelson35190502008-04-22 14:48:55 -0500133 .ctl_name = CTL_UNNUMBERED,
134 .procname = "xpc",
135 .mode = 0555,
136 .child = xpc_sys_xpc_dir},
Eric W. Biederman68cbf072007-02-14 00:33:41 -0800137 {}
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700138};
139static struct ctl_table_header *xpc_sysctl;
140
Dean Nelsona47d5da2008-07-29 22:34:09 -0700141/* non-zero if any remote partition disengage was timed out */
142int xpc_disengage_timedout;
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700143
Dean Nelson6e410172008-07-29 22:34:09 -0700144/* #of activate IRQs received */
145atomic_t xpc_activate_IRQ_rcvd = ATOMIC_INIT(0);
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700146
147/* IRQ handler notifies this wait queue on receipt of an IRQ */
Dean Nelson6e410172008-07-29 22:34:09 -0700148DECLARE_WAIT_QUEUE_HEAD(xpc_activate_IRQ_wq);
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700149
150static unsigned long xpc_hb_check_timeout;
Dean Nelson33ba3c72008-07-29 22:34:07 -0700151static struct timer_list xpc_hb_timer;
152void *xpc_heartbeating_to_mask;
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700153
Dean Nelsone54af722005-10-25 14:07:43 -0500154/* notification that the xpc_hb_checker thread has exited */
Jes Sorensenf9e505a2006-01-17 12:52:21 -0500155static DECLARE_COMPLETION(xpc_hb_checker_exited);
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700156
Dean Nelsone54af722005-10-25 14:07:43 -0500157/* notification that the xpc_discovery thread has exited */
Jes Sorensenf9e505a2006-01-17 12:52:21 -0500158static DECLARE_COMPLETION(xpc_discovery_exited);
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700159
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700160static void xpc_kthread_waitmsgs(struct xpc_partition *, struct xpc_channel *);
161
Dean Nelsona607c382005-09-01 14:01:37 -0500162static int xpc_system_reboot(struct notifier_block *, unsigned long, void *);
163static struct notifier_block xpc_reboot_notifier = {
164 .notifier_call = xpc_system_reboot,
165};
166
Dean Nelson780d09e2005-11-09 14:41:57 -0600167static int xpc_system_die(struct notifier_block *, unsigned long, void *);
168static struct notifier_block xpc_die_notifier = {
169 .notifier_call = xpc_system_die,
170};
171
Dean Nelson261f3b42008-07-29 22:34:16 -0700172enum xp_retval (*xpc_get_partition_rsvd_page_pa) (u64 buf, u64 *cookie,
173 u64 *paddr, size_t *len);
Dean Nelson94bd2702008-07-29 22:34:05 -0700174enum xp_retval (*xpc_rsvd_page_init) (struct xpc_rsvd_page *rp);
Dean Nelson33ba3c72008-07-29 22:34:07 -0700175void (*xpc_heartbeat_init) (void);
176void (*xpc_heartbeat_exit) (void);
177void (*xpc_increment_heartbeat) (void);
178void (*xpc_offline_heartbeat) (void);
179void (*xpc_online_heartbeat) (void);
180void (*xpc_check_remote_hb) (void);
181
Dean Nelsone17d4162008-07-29 22:34:06 -0700182enum xp_retval (*xpc_make_first_contact) (struct xpc_partition *part);
Dean Nelsona47d5da2008-07-29 22:34:09 -0700183void (*xpc_notify_senders_of_disconnect) (struct xpc_channel *ch);
Dean Nelson7fb5e592008-07-29 22:34:10 -0700184u64 (*xpc_get_chctl_all_flags) (struct xpc_partition *part);
Dean Nelson185c3a12008-07-29 22:34:11 -0700185enum xp_retval (*xpc_allocate_msgqueues) (struct xpc_channel *ch);
186void (*xpc_free_msgqueues) (struct xpc_channel *ch);
Dean Nelson7fb5e592008-07-29 22:34:10 -0700187void (*xpc_process_msg_chctl_flags) (struct xpc_partition *part, int ch_number);
Dean Nelsona47d5da2008-07-29 22:34:09 -0700188int (*xpc_n_of_deliverable_msgs) (struct xpc_channel *ch);
Dean Nelsone17d4162008-07-29 22:34:06 -0700189struct xpc_msg *(*xpc_get_deliverable_msg) (struct xpc_channel *ch);
Dean Nelson33ba3c72008-07-29 22:34:07 -0700190
Dean Nelsona47d5da2008-07-29 22:34:09 -0700191void (*xpc_request_partition_activation) (struct xpc_rsvd_page *remote_rp,
192 u64 remote_rp_pa, int nasid);
193void (*xpc_request_partition_reactivation) (struct xpc_partition *part);
194void (*xpc_request_partition_deactivation) (struct xpc_partition *part);
195void (*xpc_cancel_partition_deactivation_request) (struct xpc_partition *part);
Dean Nelson33ba3c72008-07-29 22:34:07 -0700196
Dean Nelson6e410172008-07-29 22:34:09 -0700197void (*xpc_process_activate_IRQ_rcvd) (int n_IRQs_expected);
Dean Nelsone17d4162008-07-29 22:34:06 -0700198enum xp_retval (*xpc_setup_infrastructure) (struct xpc_partition *part);
199void (*xpc_teardown_infrastructure) (struct xpc_partition *part);
200
Dean Nelsona47d5da2008-07-29 22:34:09 -0700201void (*xpc_indicate_partition_engaged) (struct xpc_partition *part);
202int (*xpc_partition_engaged) (short partid);
203int (*xpc_any_partition_engaged) (void);
204void (*xpc_indicate_partition_disengaged) (struct xpc_partition *part);
205void (*xpc_assume_partition_disengaged) (short partid);
Dean Nelson33ba3c72008-07-29 22:34:07 -0700206
Dean Nelson7fb5e592008-07-29 22:34:10 -0700207void (*xpc_send_chctl_closerequest) (struct xpc_channel *ch,
Dean Nelsona47d5da2008-07-29 22:34:09 -0700208 unsigned long *irq_flags);
Dean Nelson7fb5e592008-07-29 22:34:10 -0700209void (*xpc_send_chctl_closereply) (struct xpc_channel *ch,
210 unsigned long *irq_flags);
211void (*xpc_send_chctl_openrequest) (struct xpc_channel *ch,
Dean Nelsona47d5da2008-07-29 22:34:09 -0700212 unsigned long *irq_flags);
Dean Nelson7fb5e592008-07-29 22:34:10 -0700213void (*xpc_send_chctl_openreply) (struct xpc_channel *ch,
214 unsigned long *irq_flags);
Dean Nelson33ba3c72008-07-29 22:34:07 -0700215
Dean Nelson97bf1aa2008-07-29 22:34:08 -0700216enum xp_retval (*xpc_send_msg) (struct xpc_channel *ch, u32 flags,
217 void *payload, u16 payload_size, u8 notify_type,
218 xpc_notify_func func, void *key);
Dean Nelson33ba3c72008-07-29 22:34:07 -0700219void (*xpc_received_msg) (struct xpc_channel *ch, struct xpc_msg *msg);
Dean Nelson94bd2702008-07-29 22:34:05 -0700220
Dean Nelsona607c382005-09-01 14:01:37 -0500221/*
Dean Nelsona47d5da2008-07-29 22:34:09 -0700222 * Timer function to enforce the timelimit on the partition disengage.
Dean Nelsona607c382005-09-01 14:01:37 -0500223 */
224static void
Dean Nelsona47d5da2008-07-29 22:34:09 -0700225xpc_timeout_partition_disengage(unsigned long data)
Dean Nelsona607c382005-09-01 14:01:37 -0500226{
Dean Nelson35190502008-04-22 14:48:55 -0500227 struct xpc_partition *part = (struct xpc_partition *)data;
Dean Nelsona607c382005-09-01 14:01:37 -0500228
Dean Nelsona47d5da2008-07-29 22:34:09 -0700229 DBUG_ON(time_is_after_jiffies(part->disengage_timeout));
Dean Nelsona607c382005-09-01 14:01:37 -0500230
Dean Nelson35190502008-04-22 14:48:55 -0500231 (void)xpc_partition_disengaged(part);
Dean Nelsona607c382005-09-01 14:01:37 -0500232
Dean Nelsona47d5da2008-07-29 22:34:09 -0700233 DBUG_ON(part->disengage_timeout != 0);
234 DBUG_ON(xpc_partition_engaged(XPC_PARTID(part)));
Dean Nelsona607c382005-09-01 14:01:37 -0500235}
236
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700237/*
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700238 * Timer to produce the heartbeat. The timer structures function is
239 * already set when this is initially called. A tunable is used to
240 * specify when the next timeout should occur.
241 */
242static void
243xpc_hb_beater(unsigned long dummy)
244{
Dean Nelson33ba3c72008-07-29 22:34:07 -0700245 xpc_increment_heartbeat();
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700246
Dean Nelsonaaa3cd62008-07-29 22:34:07 -0700247 if (time_is_before_eq_jiffies(xpc_hb_check_timeout))
Dean Nelson6e410172008-07-29 22:34:09 -0700248 wake_up_interruptible(&xpc_activate_IRQ_wq);
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700249
250 xpc_hb_timer.expires = jiffies + (xpc_hb_interval * HZ);
251 add_timer(&xpc_hb_timer);
252}
253
Dean Nelson33ba3c72008-07-29 22:34:07 -0700254static void
255xpc_start_hb_beater(void)
256{
257 xpc_heartbeat_init();
258 init_timer(&xpc_hb_timer);
259 xpc_hb_timer.function = xpc_hb_beater;
260 xpc_hb_beater(0);
261}
262
263static void
264xpc_stop_hb_beater(void)
265{
266 del_timer_sync(&xpc_hb_timer);
267 xpc_heartbeat_exit();
268}
269
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700270/*
271 * This thread is responsible for nearly all of the partition
272 * activation/deactivation.
273 */
274static int
275xpc_hb_checker(void *ignore)
276{
277 int last_IRQ_count = 0;
278 int new_IRQ_count;
Dean Nelson35190502008-04-22 14:48:55 -0500279 int force_IRQ = 0;
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700280
281 /* this thread was marked active by xpc_hb_init() */
282
Mike Travis0bc3cc02008-07-24 18:21:31 -0700283 set_cpus_allowed_ptr(current, &cpumask_of_cpu(XPC_HB_CHECK_CPU));
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700284
Dean Nelson4c013f52007-11-07 07:53:06 -0600285 /* set our heartbeating to other partitions into motion */
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700286 xpc_hb_check_timeout = jiffies + (xpc_hb_check_interval * HZ);
Dean Nelson33ba3c72008-07-29 22:34:07 -0700287 xpc_start_hb_beater();
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700288
Dean Nelson2c2b94f2008-04-22 14:50:17 -0500289 while (!xpc_exiting) {
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700290
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700291 dev_dbg(xpc_part, "woke up with %d ticks rem; %d IRQs have "
292 "been received\n",
Dean Nelson35190502008-04-22 14:48:55 -0500293 (int)(xpc_hb_check_timeout - jiffies),
Dean Nelson6e410172008-07-29 22:34:09 -0700294 atomic_read(&xpc_activate_IRQ_rcvd) - last_IRQ_count);
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700295
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700296 /* checking of remote heartbeats is skewed by IRQ handling */
Dean Nelsonaaa3cd62008-07-29 22:34:07 -0700297 if (time_is_before_eq_jiffies(xpc_hb_check_timeout)) {
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700298 dev_dbg(xpc_part, "checking remote heartbeats\n");
299 xpc_check_remote_hb();
300
301 /*
302 * We need to periodically recheck to ensure no
Dean Nelsonc39838c2008-07-29 22:34:11 -0700303 * IRQ/amo pairs have been missed. That check
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700304 * must always reset xpc_hb_check_timeout.
305 */
306 force_IRQ = 1;
307 }
308
Dean Nelsona607c382005-09-01 14:01:37 -0500309 /* check for outstanding IRQs */
Dean Nelson6e410172008-07-29 22:34:09 -0700310 new_IRQ_count = atomic_read(&xpc_activate_IRQ_rcvd);
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700311 if (last_IRQ_count < new_IRQ_count || force_IRQ != 0) {
312 force_IRQ = 0;
313
314 dev_dbg(xpc_part, "found an IRQ to process; will be "
315 "resetting xpc_hb_check_timeout\n");
316
Dean Nelson6e410172008-07-29 22:34:09 -0700317 xpc_process_activate_IRQ_rcvd(new_IRQ_count -
318 last_IRQ_count);
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700319 last_IRQ_count = new_IRQ_count;
320
321 xpc_hb_check_timeout = jiffies +
Dean Nelson35190502008-04-22 14:48:55 -0500322 (xpc_hb_check_interval * HZ);
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700323 }
Dean Nelsona607c382005-09-01 14:01:37 -0500324
325 /* wait for IRQ or timeout */
Dean Nelson6e410172008-07-29 22:34:09 -0700326 (void)wait_event_interruptible(xpc_activate_IRQ_wq,
327 (last_IRQ_count < atomic_read(
328 &xpc_activate_IRQ_rcvd)
Dean Nelsonaaa3cd62008-07-29 22:34:07 -0700329 || time_is_before_eq_jiffies(
330 xpc_hb_check_timeout) ||
Dean Nelson2c2b94f2008-04-22 14:50:17 -0500331 xpc_exiting));
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700332 }
333
Dean Nelson33ba3c72008-07-29 22:34:07 -0700334 xpc_stop_hb_beater();
335
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700336 dev_dbg(xpc_part, "heartbeat checker is exiting\n");
337
Dean Nelsone54af722005-10-25 14:07:43 -0500338 /* mark this thread as having exited */
Jes Sorensenf9e505a2006-01-17 12:52:21 -0500339 complete(&xpc_hb_checker_exited);
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700340 return 0;
341}
342
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700343/*
344 * This thread will attempt to discover other partitions to activate
345 * based on info provided by SAL. This new thread is short lived and
346 * will exit once discovery is complete.
347 */
348static int
349xpc_initiate_discovery(void *ignore)
350{
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700351 xpc_discovery();
352
353 dev_dbg(xpc_part, "discovery thread is exiting\n");
354
Dean Nelsone54af722005-10-25 14:07:43 -0500355 /* mark this thread as having exited */
Jes Sorensenf9e505a2006-01-17 12:52:21 -0500356 complete(&xpc_discovery_exited);
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700357 return 0;
358}
359
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700360/*
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700361 * The first kthread assigned to a newly activated partition is the one
Dean Nelsone17d4162008-07-29 22:34:06 -0700362 * created by XPC HB with which it calls xpc_activating(). XPC hangs on to
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700363 * that kthread until the partition is brought down, at which time that kthread
364 * returns back to XPC HB. (The return of that kthread will signify to XPC HB
365 * that XPC has dismantled all communication infrastructure for the associated
366 * partition.) This kthread becomes the channel manager for that partition.
367 *
368 * Each active partition has a channel manager, who, besides connecting and
369 * disconnecting channels, will ensure that each of the partition's connected
370 * channels has the required number of assigned kthreads to get the work done.
371 */
372static void
373xpc_channel_mgr(struct xpc_partition *part)
374{
375 while (part->act_state != XPC_P_DEACTIVATING ||
Dean Nelson35190502008-04-22 14:48:55 -0500376 atomic_read(&part->nchannels_active) > 0 ||
377 !xpc_partition_disengaged(part)) {
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700378
Dean Nelson7fb5e592008-07-29 22:34:10 -0700379 xpc_process_sent_chctl_flags(part);
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700380
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700381 /*
382 * Wait until we've been requested to activate kthreads or
383 * all of the channel's message queues have been torn down or
384 * a signal is pending.
385 *
386 * The channel_mgr_requests is set to 1 after being awakened,
387 * This is done to prevent the channel mgr from making one pass
388 * through the loop for each request, since he will
389 * be servicing all the requests in one pass. The reason it's
390 * set to 1 instead of 0 is so that other kthreads will know
391 * that the channel mgr is running and won't bother trying to
392 * wake him up.
393 */
394 atomic_dec(&part->channel_mgr_requests);
Dean Nelson35190502008-04-22 14:48:55 -0500395 (void)wait_event_interruptible(part->channel_mgr_wq,
Dean Nelson2c2b94f2008-04-22 14:50:17 -0500396 (atomic_read(&part->channel_mgr_requests) > 0 ||
Dean Nelson7fb5e592008-07-29 22:34:10 -0700397 part->chctl.all_flags != 0 ||
Dean Nelson2c2b94f2008-04-22 14:50:17 -0500398 (part->act_state == XPC_P_DEACTIVATING &&
399 atomic_read(&part->nchannels_active) == 0 &&
400 xpc_partition_disengaged(part))));
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700401 atomic_set(&part->channel_mgr_requests, 1);
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700402 }
403}
404
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700405/*
406 * When XPC HB determines that a partition has come up, it will create a new
407 * kthread and that kthread will call this function to attempt to set up the
408 * basic infrastructure used for Cross Partition Communication with the newly
409 * upped partition.
410 *
411 * The kthread that was created by XPC HB and which setup the XPC
Dean Nelsone17d4162008-07-29 22:34:06 -0700412 * infrastructure will remain assigned to the partition becoming the channel
413 * manager for that partition until the partition is deactivating, at which
414 * time the kthread will teardown the XPC infrastructure and then exit.
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700415 */
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700416static int
417xpc_activating(void *__partid)
418{
Dean Nelson64d032b2008-05-12 14:02:03 -0700419 short partid = (u64)__partid;
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700420 struct xpc_partition *part = &xpc_partitions[partid];
421 unsigned long irq_flags;
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700422
Dean Nelsonbc63d382008-07-29 22:34:04 -0700423 DBUG_ON(partid < 0 || partid >= xp_max_npartitions);
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700424
425 spin_lock_irqsave(&part->act_lock, irq_flags);
426
427 if (part->act_state == XPC_P_DEACTIVATING) {
428 part->act_state = XPC_P_INACTIVE;
429 spin_unlock_irqrestore(&part->act_lock, irq_flags);
430 part->remote_rp_pa = 0;
431 return 0;
432 }
433
434 /* indicate the thread is activating */
435 DBUG_ON(part->act_state != XPC_P_ACTIVATION_REQ);
436 part->act_state = XPC_P_ACTIVATING;
437
438 XPC_SET_REASON(part, 0, 0);
439 spin_unlock_irqrestore(&part->act_lock, irq_flags);
440
Dean Nelsone17d4162008-07-29 22:34:06 -0700441 dev_dbg(xpc_part, "activating partition %d\n", partid);
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700442
Dean Nelson33ba3c72008-07-29 22:34:07 -0700443 xpc_allow_hb(partid);
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700444
Dean Nelsone17d4162008-07-29 22:34:06 -0700445 if (xpc_setup_infrastructure(part) == xpSuccess) {
446 (void)xpc_part_ref(part); /* this will always succeed */
447
448 if (xpc_make_first_contact(part) == xpSuccess) {
449 xpc_mark_partition_active(part);
450 xpc_channel_mgr(part);
451 /* won't return until partition is deactivating */
452 }
453
454 xpc_part_deref(part);
455 xpc_teardown_infrastructure(part);
456 }
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700457
Dean Nelson33ba3c72008-07-29 22:34:07 -0700458 xpc_disallow_hb(partid);
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700459 xpc_mark_partition_inactive(part);
460
Dean Nelson65c17b82008-05-12 14:02:02 -0700461 if (part->reason == xpReactivating) {
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700462 /* interrupting ourselves results in activating partition */
Dean Nelsona47d5da2008-07-29 22:34:09 -0700463 xpc_request_partition_reactivation(part);
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700464 }
465
466 return 0;
467}
468
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700469void
470xpc_activate_partition(struct xpc_partition *part)
471{
Dean Nelson64d032b2008-05-12 14:02:03 -0700472 short partid = XPC_PARTID(part);
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700473 unsigned long irq_flags;
Dean Nelson2c2b94f2008-04-22 14:50:17 -0500474 struct task_struct *kthread;
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700475
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700476 spin_lock_irqsave(&part->act_lock, irq_flags);
477
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700478 DBUG_ON(part->act_state != XPC_P_INACTIVE);
479
Robin Holt7c6c6632006-02-02 12:30:21 -0600480 part->act_state = XPC_P_ACTIVATION_REQ;
Dean Nelson65c17b82008-05-12 14:02:02 -0700481 XPC_SET_REASON(part, xpCloneKThread, __LINE__);
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700482
483 spin_unlock_irqrestore(&part->act_lock, irq_flags);
Robin Holt7c6c6632006-02-02 12:30:21 -0600484
Dean Nelson2c2b94f2008-04-22 14:50:17 -0500485 kthread = kthread_run(xpc_activating, (void *)((u64)partid), "xpc%02d",
486 partid);
487 if (IS_ERR(kthread)) {
Robin Holt7c6c6632006-02-02 12:30:21 -0600488 spin_lock_irqsave(&part->act_lock, irq_flags);
489 part->act_state = XPC_P_INACTIVE;
Dean Nelson65c17b82008-05-12 14:02:02 -0700490 XPC_SET_REASON(part, xpCloneKThreadFailed, __LINE__);
Robin Holt7c6c6632006-02-02 12:30:21 -0600491 spin_unlock_irqrestore(&part->act_lock, irq_flags);
492 }
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700493}
494
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700495void
496xpc_activate_kthreads(struct xpc_channel *ch, int needed)
497{
498 int idle = atomic_read(&ch->kthreads_idle);
499 int assigned = atomic_read(&ch->kthreads_assigned);
500 int wakeup;
501
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700502 DBUG_ON(needed <= 0);
503
504 if (idle > 0) {
505 wakeup = (needed > idle) ? idle : needed;
506 needed -= wakeup;
507
508 dev_dbg(xpc_chan, "wakeup %d idle kthreads, partid=%d, "
509 "channel=%d\n", wakeup, ch->partid, ch->number);
510
511 /* only wakeup the requested number of kthreads */
512 wake_up_nr(&ch->idle_wq, wakeup);
513 }
514
Dean Nelson2c2b94f2008-04-22 14:50:17 -0500515 if (needed <= 0)
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700516 return;
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700517
518 if (needed + assigned > ch->kthreads_assigned_limit) {
519 needed = ch->kthreads_assigned_limit - assigned;
Dean Nelson2c2b94f2008-04-22 14:50:17 -0500520 if (needed <= 0)
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700521 return;
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700522 }
523
524 dev_dbg(xpc_chan, "create %d new kthreads, partid=%d, channel=%d\n",
525 needed, ch->partid, ch->number);
526
Dean Nelsona460ef82006-11-22 08:25:00 -0600527 xpc_create_kthreads(ch, needed, 0);
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700528}
529
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700530/*
531 * This function is where XPC's kthreads wait for messages to deliver.
532 */
533static void
534xpc_kthread_waitmsgs(struct xpc_partition *part, struct xpc_channel *ch)
535{
536 do {
537 /* deliver messages to their intended recipients */
538
Dean Nelsona47d5da2008-07-29 22:34:09 -0700539 while (xpc_n_of_deliverable_msgs(ch) > 0 &&
Dean Nelson2c2b94f2008-04-22 14:50:17 -0500540 !(ch->flags & XPC_C_DISCONNECTING)) {
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700541 xpc_deliver_msg(ch);
542 }
543
544 if (atomic_inc_return(&ch->kthreads_idle) >
Dean Nelson35190502008-04-22 14:48:55 -0500545 ch->kthreads_idle_limit) {
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700546 /* too many idle kthreads on this channel */
547 atomic_dec(&ch->kthreads_idle);
548 break;
549 }
550
551 dev_dbg(xpc_chan, "idle kthread calling "
552 "wait_event_interruptible_exclusive()\n");
553
Dean Nelson35190502008-04-22 14:48:55 -0500554 (void)wait_event_interruptible_exclusive(ch->idle_wq,
Dean Nelsona47d5da2008-07-29 22:34:09 -0700555 (xpc_n_of_deliverable_msgs(ch) > 0 ||
Dean Nelson2c2b94f2008-04-22 14:50:17 -0500556 (ch->flags & XPC_C_DISCONNECTING)));
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700557
558 atomic_dec(&ch->kthreads_idle);
559
Dean Nelson2c2b94f2008-04-22 14:50:17 -0500560 } while (!(ch->flags & XPC_C_DISCONNECTING));
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700561}
562
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700563static int
Dean Nelson2c2b94f2008-04-22 14:50:17 -0500564xpc_kthread_start(void *args)
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700565{
Dean Nelson64d032b2008-05-12 14:02:03 -0700566 short partid = XPC_UNPACK_ARG1(args);
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700567 u16 ch_number = XPC_UNPACK_ARG2(args);
568 struct xpc_partition *part = &xpc_partitions[partid];
569 struct xpc_channel *ch;
570 int n_needed;
Dean Nelsone54af722005-10-25 14:07:43 -0500571 unsigned long irq_flags;
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700572
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700573 dev_dbg(xpc_chan, "kthread starting, partid=%d, channel=%d\n",
574 partid, ch_number);
575
576 ch = &part->channels[ch_number];
577
578 if (!(ch->flags & XPC_C_DISCONNECTING)) {
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700579
580 /* let registerer know that connection has been established */
581
Dean Nelsone54af722005-10-25 14:07:43 -0500582 spin_lock_irqsave(&ch->lock, irq_flags);
Dean Nelson4c2cd962006-02-15 08:02:21 -0600583 if (!(ch->flags & XPC_C_CONNECTEDCALLOUT)) {
584 ch->flags |= XPC_C_CONNECTEDCALLOUT;
Dean Nelsone54af722005-10-25 14:07:43 -0500585 spin_unlock_irqrestore(&ch->lock, irq_flags);
586
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700587 xpc_connected_callout(ch);
588
Dean Nelson4c2cd962006-02-15 08:02:21 -0600589 spin_lock_irqsave(&ch->lock, irq_flags);
590 ch->flags |= XPC_C_CONNECTEDCALLOUT_MADE;
591 spin_unlock_irqrestore(&ch->lock, irq_flags);
592
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700593 /*
594 * It is possible that while the callout was being
595 * made that the remote partition sent some messages.
596 * If that is the case, we may need to activate
597 * additional kthreads to help deliver them. We only
598 * need one less than total #of messages to deliver.
599 */
Dean Nelsona47d5da2008-07-29 22:34:09 -0700600 n_needed = xpc_n_of_deliverable_msgs(ch) - 1;
Dean Nelson2c2b94f2008-04-22 14:50:17 -0500601 if (n_needed > 0 && !(ch->flags & XPC_C_DISCONNECTING))
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700602 xpc_activate_kthreads(ch, n_needed);
Dean Nelson2c2b94f2008-04-22 14:50:17 -0500603
Dean Nelsone54af722005-10-25 14:07:43 -0500604 } else {
605 spin_unlock_irqrestore(&ch->lock, irq_flags);
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700606 }
607
608 xpc_kthread_waitmsgs(part, ch);
609 }
610
Dean Nelsona460ef82006-11-22 08:25:00 -0600611 /* let registerer know that connection is disconnecting */
Dean Nelsone54af722005-10-25 14:07:43 -0500612
Dean Nelsona460ef82006-11-22 08:25:00 -0600613 spin_lock_irqsave(&ch->lock, irq_flags);
614 if ((ch->flags & XPC_C_CONNECTEDCALLOUT_MADE) &&
Dean Nelson35190502008-04-22 14:48:55 -0500615 !(ch->flags & XPC_C_DISCONNECTINGCALLOUT)) {
Dean Nelsona460ef82006-11-22 08:25:00 -0600616 ch->flags |= XPC_C_DISCONNECTINGCALLOUT;
Dean Nelson4c2cd962006-02-15 08:02:21 -0600617 spin_unlock_irqrestore(&ch->lock, irq_flags);
Dean Nelsona460ef82006-11-22 08:25:00 -0600618
Dean Nelson65c17b82008-05-12 14:02:02 -0700619 xpc_disconnect_callout(ch, xpDisconnecting);
Dean Nelsona460ef82006-11-22 08:25:00 -0600620
621 spin_lock_irqsave(&ch->lock, irq_flags);
622 ch->flags |= XPC_C_DISCONNECTINGCALLOUT_MADE;
623 }
624 spin_unlock_irqrestore(&ch->lock, irq_flags);
625
Dean Nelsona47d5da2008-07-29 22:34:09 -0700626 if (atomic_dec_return(&ch->kthreads_assigned) == 0 &&
627 atomic_dec_return(&part->nchannels_engaged) == 0) {
628 xpc_indicate_partition_disengaged(part);
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700629 }
630
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700631 xpc_msgqueue_deref(ch);
632
633 dev_dbg(xpc_chan, "kthread exiting, partid=%d, channel=%d\n",
634 partid, ch_number);
635
636 xpc_part_deref(part);
637 return 0;
638}
639
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700640/*
641 * For each partition that XPC has established communications with, there is
642 * a minimum of one kernel thread assigned to perform any operation that
643 * may potentially sleep or block (basically the callouts to the asynchronous
644 * functions registered via xpc_connect()).
645 *
646 * Additional kthreads are created and destroyed by XPC as the workload
647 * demands.
648 *
649 * A kthread is assigned to one of the active channels that exists for a given
650 * partition.
651 */
652void
Dean Nelsona460ef82006-11-22 08:25:00 -0600653xpc_create_kthreads(struct xpc_channel *ch, int needed,
Dean Nelson35190502008-04-22 14:48:55 -0500654 int ignore_disconnecting)
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700655{
656 unsigned long irq_flags;
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700657 u64 args = XPC_PACK_ARGS(ch->partid, ch->number);
Dean Nelsona607c382005-09-01 14:01:37 -0500658 struct xpc_partition *part = &xpc_partitions[ch->partid];
Dean Nelson2c2b94f2008-04-22 14:50:17 -0500659 struct task_struct *kthread;
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700660
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700661 while (needed-- > 0) {
Dean Nelsone54af722005-10-25 14:07:43 -0500662
663 /*
664 * The following is done on behalf of the newly created
665 * kthread. That kthread is responsible for doing the
666 * counterpart to the following before it exits.
667 */
Dean Nelsona460ef82006-11-22 08:25:00 -0600668 if (ignore_disconnecting) {
669 if (!atomic_inc_not_zero(&ch->kthreads_assigned)) {
670 /* kthreads assigned had gone to zero */
671 BUG_ON(!(ch->flags &
Dean Nelson35190502008-04-22 14:48:55 -0500672 XPC_C_DISCONNECTINGCALLOUT_MADE));
Dean Nelsona460ef82006-11-22 08:25:00 -0600673 break;
674 }
675
676 } else if (ch->flags & XPC_C_DISCONNECTING) {
677 break;
678
Dean Nelsona47d5da2008-07-29 22:34:09 -0700679 } else if (atomic_inc_return(&ch->kthreads_assigned) == 1 &&
680 atomic_inc_return(&part->nchannels_engaged) == 1) {
681 xpc_indicate_partition_engaged(part);
Dean Nelsona460ef82006-11-22 08:25:00 -0600682 }
Dean Nelson35190502008-04-22 14:48:55 -0500683 (void)xpc_part_ref(part);
Dean Nelsone54af722005-10-25 14:07:43 -0500684 xpc_msgqueue_ref(ch);
Dean Nelsone54af722005-10-25 14:07:43 -0500685
Dean Nelson2c2b94f2008-04-22 14:50:17 -0500686 kthread = kthread_run(xpc_kthread_start, (void *)args,
687 "xpc%02dc%d", ch->partid, ch->number);
688 if (IS_ERR(kthread)) {
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700689 /* the fork failed */
Dean Nelsona460ef82006-11-22 08:25:00 -0600690
691 /*
692 * NOTE: if (ignore_disconnecting &&
693 * !(ch->flags & XPC_C_DISCONNECTINGCALLOUT)) is true,
694 * then we'll deadlock if all other kthreads assigned
695 * to this channel are blocked in the channel's
696 * registerer, because the only thing that will unblock
Dean Nelson65c17b82008-05-12 14:02:02 -0700697 * them is the xpDisconnecting callout that this
Dean Nelson2c2b94f2008-04-22 14:50:17 -0500698 * failed kthread_run() would have made.
Dean Nelsona460ef82006-11-22 08:25:00 -0600699 */
700
Dean Nelsone54af722005-10-25 14:07:43 -0500701 if (atomic_dec_return(&ch->kthreads_assigned) == 0 &&
702 atomic_dec_return(&part->nchannels_engaged) == 0) {
Dean Nelsona47d5da2008-07-29 22:34:09 -0700703 xpc_indicate_partition_disengaged(part);
Dean Nelsone54af722005-10-25 14:07:43 -0500704 }
705 xpc_msgqueue_deref(ch);
706 xpc_part_deref(part);
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700707
708 if (atomic_read(&ch->kthreads_assigned) <
Dean Nelson35190502008-04-22 14:48:55 -0500709 ch->kthreads_idle_limit) {
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700710 /*
711 * Flag this as an error only if we have an
712 * insufficient #of kthreads for the channel
713 * to function.
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700714 */
715 spin_lock_irqsave(&ch->lock, irq_flags);
Dean Nelson65c17b82008-05-12 14:02:02 -0700716 XPC_DISCONNECT_CHANNEL(ch, xpLackOfResources,
Dean Nelson35190502008-04-22 14:48:55 -0500717 &irq_flags);
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700718 spin_unlock_irqrestore(&ch->lock, irq_flags);
719 }
720 break;
721 }
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700722 }
723}
724
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700725void
726xpc_disconnect_wait(int ch_number)
727{
Dean Nelsona607c382005-09-01 14:01:37 -0500728 unsigned long irq_flags;
Dean Nelson64d032b2008-05-12 14:02:03 -0700729 short partid;
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700730 struct xpc_partition *part;
731 struct xpc_channel *ch;
Dean Nelsone54af722005-10-25 14:07:43 -0500732 int wakeup_channel_mgr;
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700733
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700734 /* now wait for all callouts to the caller's function to cease */
Dean Nelsonbc63d382008-07-29 22:34:04 -0700735 for (partid = 0; partid < xp_max_npartitions; partid++) {
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700736 part = &xpc_partitions[partid];
737
Dean Nelson2c2b94f2008-04-22 14:50:17 -0500738 if (!xpc_part_ref(part))
Dean Nelsone54af722005-10-25 14:07:43 -0500739 continue;
Dean Nelsone54af722005-10-25 14:07:43 -0500740
741 ch = &part->channels[ch_number];
742
743 if (!(ch->flags & XPC_C_WDISCONNECT)) {
744 xpc_part_deref(part);
745 continue;
746 }
747
Jes Sorensenf9e505a2006-01-17 12:52:21 -0500748 wait_for_completion(&ch->wdisconnect_wait);
Dean Nelsone54af722005-10-25 14:07:43 -0500749
750 spin_lock_irqsave(&ch->lock, irq_flags);
751 DBUG_ON(!(ch->flags & XPC_C_DISCONNECTED));
752 wakeup_channel_mgr = 0;
753
Dean Nelson7fb5e592008-07-29 22:34:10 -0700754 if (ch->delayed_chctl_flags) {
Dean Nelsone54af722005-10-25 14:07:43 -0500755 if (part->act_state != XPC_P_DEACTIVATING) {
Dean Nelson7fb5e592008-07-29 22:34:10 -0700756 spin_lock(&part->chctl_lock);
757 part->chctl.flags[ch->number] |=
758 ch->delayed_chctl_flags;
759 spin_unlock(&part->chctl_lock);
Dean Nelsone54af722005-10-25 14:07:43 -0500760 wakeup_channel_mgr = 1;
761 }
Dean Nelson7fb5e592008-07-29 22:34:10 -0700762 ch->delayed_chctl_flags = 0;
Dean Nelsone54af722005-10-25 14:07:43 -0500763 }
764
765 ch->flags &= ~XPC_C_WDISCONNECT;
766 spin_unlock_irqrestore(&ch->lock, irq_flags);
767
Dean Nelson2c2b94f2008-04-22 14:50:17 -0500768 if (wakeup_channel_mgr)
Dean Nelsone54af722005-10-25 14:07:43 -0500769 xpc_wakeup_channel_mgr(part);
Dean Nelsone54af722005-10-25 14:07:43 -0500770
771 xpc_part_deref(part);
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700772 }
773}
774
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700775static void
Dean Nelson65c17b82008-05-12 14:02:02 -0700776xpc_do_exit(enum xp_retval reason)
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700777{
Dean Nelson64d032b2008-05-12 14:02:03 -0700778 short partid;
Dean Nelson1ecaded2006-01-06 09:48:21 -0600779 int active_part_count, printed_waiting_msg = 0;
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700780 struct xpc_partition *part;
Dean Nelsona47d5da2008-07-29 22:34:09 -0700781 unsigned long printmsg_time, disengage_timeout = 0;
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700782
Dean Nelsona607c382005-09-01 14:01:37 -0500783 /* a 'rmmod XPC' and a 'reboot' cannot both end up here together */
784 DBUG_ON(xpc_exiting == 1);
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700785
786 /*
Dean Nelsona607c382005-09-01 14:01:37 -0500787 * Let the heartbeat checker thread and the discovery thread
788 * (if one is running) know that they should exit. Also wake up
789 * the heartbeat checker thread in case it's sleeping.
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700790 */
791 xpc_exiting = 1;
Dean Nelson6e410172008-07-29 22:34:09 -0700792 wake_up_interruptible(&xpc_activate_IRQ_wq);
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700793
Dean Nelsone54af722005-10-25 14:07:43 -0500794 /* wait for the discovery thread to exit */
Jes Sorensenf9e505a2006-01-17 12:52:21 -0500795 wait_for_completion(&xpc_discovery_exited);
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700796
Dean Nelsone54af722005-10-25 14:07:43 -0500797 /* wait for the heartbeat checker thread to exit */
Jes Sorensenf9e505a2006-01-17 12:52:21 -0500798 wait_for_completion(&xpc_hb_checker_exited);
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700799
Dean Nelsona607c382005-09-01 14:01:37 -0500800 /* sleep for a 1/3 of a second or so */
Dean Nelson35190502008-04-22 14:48:55 -0500801 (void)msleep_interruptible(300);
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700802
803 /* wait for all partitions to become inactive */
804
Dean Nelsona47d5da2008-07-29 22:34:09 -0700805 printmsg_time = jiffies + (XPC_DEACTIVATE_PRINTMSG_INTERVAL * HZ);
806 xpc_disengage_timedout = 0;
Dean Nelsona607c382005-09-01 14:01:37 -0500807
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700808 do {
809 active_part_count = 0;
810
Dean Nelsonbc63d382008-07-29 22:34:04 -0700811 for (partid = 0; partid < xp_max_npartitions; partid++) {
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700812 part = &xpc_partitions[partid];
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700813
Dean Nelsona607c382005-09-01 14:01:37 -0500814 if (xpc_partition_disengaged(part) &&
Dean Nelson35190502008-04-22 14:48:55 -0500815 part->act_state == XPC_P_INACTIVE) {
Dean Nelsona607c382005-09-01 14:01:37 -0500816 continue;
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700817 }
Dean Nelsona607c382005-09-01 14:01:37 -0500818
819 active_part_count++;
820
821 XPC_DEACTIVATE_PARTITION(part, reason);
Dean Nelson1ecaded2006-01-06 09:48:21 -0600822
Dean Nelsona47d5da2008-07-29 22:34:09 -0700823 if (part->disengage_timeout > disengage_timeout)
824 disengage_timeout = part->disengage_timeout;
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700825 }
826
Dean Nelsona47d5da2008-07-29 22:34:09 -0700827 if (xpc_any_partition_engaged()) {
Dean Nelsonaaa3cd62008-07-29 22:34:07 -0700828 if (time_is_before_jiffies(printmsg_time)) {
Dean Nelson1ecaded2006-01-06 09:48:21 -0600829 dev_info(xpc_part, "waiting for remote "
Dean Nelsona47d5da2008-07-29 22:34:09 -0700830 "partitions to deactivate, timeout in "
831 "%ld seconds\n", (disengage_timeout -
832 jiffies) / HZ);
Dean Nelson1ecaded2006-01-06 09:48:21 -0600833 printmsg_time = jiffies +
Dean Nelsona47d5da2008-07-29 22:34:09 -0700834 (XPC_DEACTIVATE_PRINTMSG_INTERVAL * HZ);
Dean Nelson1ecaded2006-01-06 09:48:21 -0600835 printed_waiting_msg = 1;
836 }
837
838 } else if (active_part_count > 0) {
839 if (printed_waiting_msg) {
840 dev_info(xpc_part, "waiting for local partition"
Dean Nelsona47d5da2008-07-29 22:34:09 -0700841 " to deactivate\n");
Dean Nelson1ecaded2006-01-06 09:48:21 -0600842 printed_waiting_msg = 0;
843 }
844
845 } else {
Dean Nelsona47d5da2008-07-29 22:34:09 -0700846 if (!xpc_disengage_timedout) {
Dean Nelson1ecaded2006-01-06 09:48:21 -0600847 dev_info(xpc_part, "all partitions have "
Dean Nelsona47d5da2008-07-29 22:34:09 -0700848 "deactivated\n");
Dean Nelson1ecaded2006-01-06 09:48:21 -0600849 }
850 break;
Dean Nelsona607c382005-09-01 14:01:37 -0500851 }
852
853 /* sleep for a 1/3 of a second or so */
Dean Nelson35190502008-04-22 14:48:55 -0500854 (void)msleep_interruptible(300);
Dean Nelsona607c382005-09-01 14:01:37 -0500855
856 } while (1);
857
Dean Nelsona47d5da2008-07-29 22:34:09 -0700858 DBUG_ON(xpc_any_partition_engaged());
Dean Nelson33ba3c72008-07-29 22:34:07 -0700859 DBUG_ON(xpc_any_hbs_allowed() != 0);
Dean Nelsona607c382005-09-01 14:01:37 -0500860
Dean Nelson81fe7882008-07-29 22:34:15 -0700861 /* a zero timestamp indicates our rsvd page is not initialized */
862 xpc_rsvd_page->ts_jiffies = 0;
Dean Nelsona607c382005-09-01 14:01:37 -0500863
Dean Nelson65c17b82008-05-12 14:02:02 -0700864 if (reason == xpUnloading) {
Dean Nelson35190502008-04-22 14:48:55 -0500865 (void)unregister_die_notifier(&xpc_die_notifier);
Dean Nelsonbc63d382008-07-29 22:34:04 -0700866 (void)unregister_reboot_notifier(&xpc_reboot_notifier);
Dean Nelson0752c672006-01-10 11:07:19 -0600867 }
Dean Nelson780d09e2005-11-09 14:41:57 -0600868
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700869 /* clear the interface to XPC's functions */
870 xpc_clear_interface();
871
Dean Nelson2c2b94f2008-04-22 14:50:17 -0500872 if (xpc_sysctl)
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700873 unregister_sysctl_table(xpc_sysctl);
Dean Nelson7682a4c2006-08-08 15:03:29 -0500874
Dean Nelsonbc63d382008-07-29 22:34:04 -0700875 kfree(xpc_partitions);
Dean Nelson6e410172008-07-29 22:34:09 -0700876
877 if (is_shub())
878 xpc_exit_sn2();
879 else
880 xpc_exit_uv();
Dean Nelson89eb8eb2005-03-23 19:50:00 -0700881}
882
Dean Nelsona607c382005-09-01 14:01:37 -0500883/*
Dean Nelsond6ad0332006-01-10 11:08:55 -0600884 * This function is called when the system is being rebooted.
885 */
886static int
887xpc_system_reboot(struct notifier_block *nb, unsigned long event, void *unused)
888{
Dean Nelson65c17b82008-05-12 14:02:02 -0700889 enum xp_retval reason;
Dean Nelsond6ad0332006-01-10 11:08:55 -0600890
Dean Nelsond6ad0332006-01-10 11:08:55 -0600891 switch (event) {
892 case SYS_RESTART:
Dean Nelson65c17b82008-05-12 14:02:02 -0700893 reason = xpSystemReboot;
Dean Nelsond6ad0332006-01-10 11:08:55 -0600894 break;
895 case SYS_HALT:
Dean Nelson65c17b82008-05-12 14:02:02 -0700896 reason = xpSystemHalt;
Dean Nelsond6ad0332006-01-10 11:08:55 -0600897 break;
898 case SYS_POWER_OFF:
Dean Nelson65c17b82008-05-12 14:02:02 -0700899 reason = xpSystemPoweroff;
Dean Nelsond6ad0332006-01-10 11:08:55 -0600900 break;
901 default:
Dean Nelson65c17b82008-05-12 14:02:02 -0700902 reason = xpSystemGoingDown;
Dean Nelsond6ad0332006-01-10 11:08:55 -0600903 }
904
905 xpc_do_exit(reason);
906 return NOTIFY_DONE;
907}
908
Dean Nelsond6ad0332006-01-10 11:08:55 -0600909/*
Dean Nelsona47d5da2008-07-29 22:34:09 -0700910 * Notify other partitions to deactivate from us by first disengaging from all
911 * references to our memory.
Dean Nelson780d09e2005-11-09 14:41:57 -0600912 */
913static void
Dean Nelsona47d5da2008-07-29 22:34:09 -0700914xpc_die_deactivate(void)
Dean Nelson780d09e2005-11-09 14:41:57 -0600915{
916 struct xpc_partition *part;
Dean Nelson64d032b2008-05-12 14:02:03 -0700917 short partid;
Dean Nelsona47d5da2008-07-29 22:34:09 -0700918 int any_engaged;
Dean Nelson261f3b42008-07-29 22:34:16 -0700919 long keep_waiting;
920 long wait_to_print;
Dean Nelson780d09e2005-11-09 14:41:57 -0600921
Dean Nelson780d09e2005-11-09 14:41:57 -0600922 /* keep xpc_hb_checker thread from doing anything (just in case) */
923 xpc_exiting = 1;
924
Dean Nelson33ba3c72008-07-29 22:34:07 -0700925 xpc_disallow_all_hbs(); /*indicate we're deactivated */
Dean Nelson780d09e2005-11-09 14:41:57 -0600926
Dean Nelsonbc63d382008-07-29 22:34:04 -0700927 for (partid = 0; partid < xp_max_npartitions; partid++) {
Dean Nelson780d09e2005-11-09 14:41:57 -0600928 part = &xpc_partitions[partid];
929
Dean Nelsona47d5da2008-07-29 22:34:09 -0700930 if (xpc_partition_engaged(partid) ||
Dean Nelson35190502008-04-22 14:48:55 -0500931 part->act_state != XPC_P_INACTIVE) {
Dean Nelsona47d5da2008-07-29 22:34:09 -0700932 xpc_request_partition_deactivation(part);
933 xpc_indicate_partition_disengaged(part);
Dean Nelson780d09e2005-11-09 14:41:57 -0600934 }
935 }
936
Dean Nelsona47d5da2008-07-29 22:34:09 -0700937 /*
938 * Though we requested that all other partitions deactivate from us,
Dean Nelson261f3b42008-07-29 22:34:16 -0700939 * we only wait until they've all disengaged or we've reached the
940 * defined timelimit.
941 *
942 * Given that one iteration through the following while-loop takes
943 * approximately 200 microseconds, calculate the #of loops to take
944 * before bailing and the #of loops before printing a waiting message.
Dean Nelsona47d5da2008-07-29 22:34:09 -0700945 */
Dean Nelson261f3b42008-07-29 22:34:16 -0700946 keep_waiting = xpc_disengage_timelimit * 1000 * 5;
947 wait_to_print = XPC_DEACTIVATE_PRINTMSG_INTERVAL * 1000 * 5;
Dean Nelson780d09e2005-11-09 14:41:57 -0600948
Dean Nelson1ecaded2006-01-06 09:48:21 -0600949 while (1) {
Dean Nelsona47d5da2008-07-29 22:34:09 -0700950 any_engaged = xpc_any_partition_engaged();
951 if (!any_engaged) {
952 dev_info(xpc_part, "all partitions have deactivated\n");
Dean Nelson1ecaded2006-01-06 09:48:21 -0600953 break;
954 }
Dean Nelson780d09e2005-11-09 14:41:57 -0600955
Dean Nelson261f3b42008-07-29 22:34:16 -0700956 if (!keep_waiting--) {
Dean Nelsonbc63d382008-07-29 22:34:04 -0700957 for (partid = 0; partid < xp_max_npartitions;
958 partid++) {
Dean Nelsona47d5da2008-07-29 22:34:09 -0700959 if (xpc_partition_engaged(partid)) {
960 dev_info(xpc_part, "deactivate from "
Dean Nelson35190502008-04-22 14:48:55 -0500961 "remote partition %d timed "
962 "out\n", partid);
Dean Nelson1ecaded2006-01-06 09:48:21 -0600963 }
964 }
965 break;
966 }
967
Dean Nelson261f3b42008-07-29 22:34:16 -0700968 if (!wait_to_print--) {
Dean Nelson780d09e2005-11-09 14:41:57 -0600969 dev_info(xpc_part, "waiting for remote partitions to "
Dean Nelsona47d5da2008-07-29 22:34:09 -0700970 "deactivate, timeout in %ld seconds\n",
Dean Nelson261f3b42008-07-29 22:34:16 -0700971 keep_waiting / (1000 * 5));
972 wait_to_print = XPC_DEACTIVATE_PRINTMSG_INTERVAL *
973 1000 * 5;
Dean Nelson780d09e2005-11-09 14:41:57 -0600974 }
Dean Nelson261f3b42008-07-29 22:34:16 -0700975
976 udelay(200);
Dean Nelson780d09e2005-11-09 14:41:57 -0600977 }
Dean Nelson780d09e2005-11-09 14:41:57 -0600978}
979
Dean Nelson780d09e2005-11-09 14:41:57 -0600980/*
Dean Nelson1f4674b2006-01-10 11:08:00 -0600981 * This function is called when the system is being restarted or halted due
982 * to some sort of system failure. If this is the case we need to notify the
983 * other partitions to disengage from all references to our memory.
984 * This function can also be called when our heartbeater could be offlined
985 * for a time. In this case we need to notify other partitions to not worry
986 * about the lack of a heartbeat.
Dean Nelson780d09e2005-11-09 14:41:57 -0600987 */
988static int
989xpc_system_die(struct notifier_block *nb, unsigned long event, void *unused)
990{
Dean Nelson261f3b42008-07-29 22:34:16 -0700991#ifdef CONFIG_IA64 /* !!! temporary kludge */
Dean Nelson780d09e2005-11-09 14:41:57 -0600992 switch (event) {
993 case DIE_MACHINE_RESTART:
994 case DIE_MACHINE_HALT:
Dean Nelsona47d5da2008-07-29 22:34:09 -0700995 xpc_die_deactivate();
Dean Nelson780d09e2005-11-09 14:41:57 -0600996 break;
Dean Nelson1f4674b2006-01-10 11:08:00 -0600997
998 case DIE_KDEBUG_ENTER:
999 /* Should lack of heartbeat be ignored by other partitions? */
Dean Nelson2c2b94f2008-04-22 14:50:17 -05001000 if (!xpc_kdebug_ignore)
Dean Nelson1f4674b2006-01-10 11:08:00 -06001001 break;
Dean Nelson2c2b94f2008-04-22 14:50:17 -05001002
Dean Nelson1f4674b2006-01-10 11:08:00 -06001003 /* fall through */
Dean Nelson780d09e2005-11-09 14:41:57 -06001004 case DIE_MCA_MONARCH_ENTER:
1005 case DIE_INIT_MONARCH_ENTER:
Dean Nelson33ba3c72008-07-29 22:34:07 -07001006 xpc_offline_heartbeat();
Dean Nelson780d09e2005-11-09 14:41:57 -06001007 break;
Dean Nelson1f4674b2006-01-10 11:08:00 -06001008
1009 case DIE_KDEBUG_LEAVE:
1010 /* Is lack of heartbeat being ignored by other partitions? */
Dean Nelson2c2b94f2008-04-22 14:50:17 -05001011 if (!xpc_kdebug_ignore)
Dean Nelson1f4674b2006-01-10 11:08:00 -06001012 break;
Dean Nelson2c2b94f2008-04-22 14:50:17 -05001013
Dean Nelson1f4674b2006-01-10 11:08:00 -06001014 /* fall through */
Dean Nelson780d09e2005-11-09 14:41:57 -06001015 case DIE_MCA_MONARCH_LEAVE:
1016 case DIE_INIT_MONARCH_LEAVE:
Dean Nelson33ba3c72008-07-29 22:34:07 -07001017 xpc_online_heartbeat();
Dean Nelson780d09e2005-11-09 14:41:57 -06001018 break;
1019 }
Dean Nelson261f3b42008-07-29 22:34:16 -07001020#else
1021 xpc_die_deactivate();
1022#endif
Dean Nelson780d09e2005-11-09 14:41:57 -06001023
1024 return NOTIFY_DONE;
1025}
1026
Dean Nelson89eb8eb2005-03-23 19:50:00 -07001027int __init
1028xpc_init(void)
1029{
1030 int ret;
Dean Nelson64d032b2008-05-12 14:02:03 -07001031 short partid;
Dean Nelson89eb8eb2005-03-23 19:50:00 -07001032 struct xpc_partition *part;
Dean Nelson2c2b94f2008-04-22 14:50:17 -05001033 struct task_struct *kthread;
Dean Nelsonee6665e2008-07-29 22:34:13 -07001034
1035 snprintf(xpc_part->bus_id, BUS_ID_SIZE, "part");
1036 snprintf(xpc_chan->bus_id, BUS_ID_SIZE, "chan");
Dean Nelson89eb8eb2005-03-23 19:50:00 -07001037
Dean Nelson94bd2702008-07-29 22:34:05 -07001038 if (is_shub()) {
1039 /*
1040 * The ia64-sn2 architecture supports at most 64 partitions.
Dean Nelsonc39838c2008-07-29 22:34:11 -07001041 * And the inability to unregister remote amos restricts us
Dean Nelson94bd2702008-07-29 22:34:05 -07001042 * further to only support exactly 64 partitions on this
1043 * architecture, no less.
1044 */
1045 if (xp_max_npartitions != 64)
1046 return -EINVAL;
1047
Dean Nelson6e410172008-07-29 22:34:09 -07001048 ret = xpc_init_sn2();
1049 if (ret != 0)
1050 return ret;
Dean Nelson94bd2702008-07-29 22:34:05 -07001051
1052 } else if (is_uv()) {
1053 xpc_init_uv();
1054
1055 } else {
Dean Nelson408865c2005-09-08 10:46:58 -05001056 return -ENODEV;
Dean Nelson94bd2702008-07-29 22:34:05 -07001057 }
Dean Nelson408865c2005-09-08 10:46:58 -05001058
Dean Nelsonbc63d382008-07-29 22:34:04 -07001059 xpc_partitions = kzalloc(sizeof(struct xpc_partition) *
1060 xp_max_npartitions, GFP_KERNEL);
1061 if (xpc_partitions == NULL) {
1062 dev_err(xpc_part, "can't get memory for partition structure\n");
1063 ret = -ENOMEM;
Dean Nelsonee6665e2008-07-29 22:34:13 -07001064 goto out_1;
Dean Nelsonbc63d382008-07-29 22:34:04 -07001065 }
Dean Nelson89eb8eb2005-03-23 19:50:00 -07001066
1067 /*
1068 * The first few fields of each entry of xpc_partitions[] need to
1069 * be initialized now so that calls to xpc_connect() and
1070 * xpc_disconnect() can be made prior to the activation of any remote
1071 * partition. NOTE THAT NONE OF THE OTHER FIELDS BELONGING TO THESE
1072 * ENTRIES ARE MEANINGFUL UNTIL AFTER AN ENTRY'S CORRESPONDING
1073 * PARTITION HAS BEEN ACTIVATED.
1074 */
Dean Nelsonbc63d382008-07-29 22:34:04 -07001075 for (partid = 0; partid < xp_max_npartitions; partid++) {
Dean Nelson89eb8eb2005-03-23 19:50:00 -07001076 part = &xpc_partitions[partid];
1077
Dean Nelson35190502008-04-22 14:48:55 -05001078 DBUG_ON((u64)part != L1_CACHE_ALIGN((u64)part));
Dean Nelson89eb8eb2005-03-23 19:50:00 -07001079
Dean Nelson6e410172008-07-29 22:34:09 -07001080 part->activate_IRQ_rcvd = 0;
Dean Nelson89eb8eb2005-03-23 19:50:00 -07001081 spin_lock_init(&part->act_lock);
1082 part->act_state = XPC_P_INACTIVE;
1083 XPC_SET_REASON(part, 0, 0);
Dean Nelsona607c382005-09-01 14:01:37 -05001084
Dean Nelsona47d5da2008-07-29 22:34:09 -07001085 init_timer(&part->disengage_timer);
1086 part->disengage_timer.function =
1087 xpc_timeout_partition_disengage;
1088 part->disengage_timer.data = (unsigned long)part;
Dean Nelsona607c382005-09-01 14:01:37 -05001089
Dean Nelson89eb8eb2005-03-23 19:50:00 -07001090 part->setup_state = XPC_P_UNSET;
1091 init_waitqueue_head(&part->teardown_wq);
1092 atomic_set(&part->references, 0);
1093 }
1094
Dean Nelsonbc63d382008-07-29 22:34:04 -07001095 xpc_sysctl = register_sysctl_table(xpc_sys_dir);
1096
Dean Nelson89eb8eb2005-03-23 19:50:00 -07001097 /*
Dean Nelson89eb8eb2005-03-23 19:50:00 -07001098 * Fill the partition reserved page with the information needed by
1099 * other partitions to discover we are alive and establish initial
1100 * communications.
1101 */
Dean Nelson94bd2702008-07-29 22:34:05 -07001102 xpc_rsvd_page = xpc_setup_rsvd_page();
Dean Nelson89eb8eb2005-03-23 19:50:00 -07001103 if (xpc_rsvd_page == NULL) {
Dean Nelsonbc63d382008-07-29 22:34:04 -07001104 dev_err(xpc_part, "can't setup our reserved page\n");
1105 ret = -EBUSY;
Dean Nelsonee6665e2008-07-29 22:34:13 -07001106 goto out_2;
Dean Nelson89eb8eb2005-03-23 19:50:00 -07001107 }
1108
Dean Nelsona607c382005-09-01 14:01:37 -05001109 /* add ourselves to the reboot_notifier_list */
1110 ret = register_reboot_notifier(&xpc_reboot_notifier);
Dean Nelson2c2b94f2008-04-22 14:50:17 -05001111 if (ret != 0)
Dean Nelsona607c382005-09-01 14:01:37 -05001112 dev_warn(xpc_part, "can't register reboot notifier\n");
Dean Nelsona607c382005-09-01 14:01:37 -05001113
Christoph Hellwig1eeb66a2007-05-08 00:27:03 -07001114 /* add ourselves to the die_notifier list */
Dean Nelson780d09e2005-11-09 14:41:57 -06001115 ret = register_die_notifier(&xpc_die_notifier);
Dean Nelson2c2b94f2008-04-22 14:50:17 -05001116 if (ret != 0)
Dean Nelson780d09e2005-11-09 14:41:57 -06001117 dev_warn(xpc_part, "can't register die notifier\n");
Dean Nelson780d09e2005-11-09 14:41:57 -06001118
Dean Nelson89eb8eb2005-03-23 19:50:00 -07001119 /*
1120 * The real work-horse behind xpc. This processes incoming
1121 * interrupts and monitors remote heartbeats.
1122 */
Dean Nelson2c2b94f2008-04-22 14:50:17 -05001123 kthread = kthread_run(xpc_hb_checker, NULL, XPC_HB_CHECK_THREAD_NAME);
1124 if (IS_ERR(kthread)) {
Dean Nelson89eb8eb2005-03-23 19:50:00 -07001125 dev_err(xpc_part, "failed while forking hb check thread\n");
Dean Nelsonbc63d382008-07-29 22:34:04 -07001126 ret = -EBUSY;
Dean Nelsonee6665e2008-07-29 22:34:13 -07001127 goto out_3;
Dean Nelson89eb8eb2005-03-23 19:50:00 -07001128 }
1129
Dean Nelson89eb8eb2005-03-23 19:50:00 -07001130 /*
1131 * Startup a thread that will attempt to discover other partitions to
1132 * activate based on info provided by SAL. This new thread is short
1133 * lived and will exit once discovery is complete.
1134 */
Dean Nelson2c2b94f2008-04-22 14:50:17 -05001135 kthread = kthread_run(xpc_initiate_discovery, NULL,
1136 XPC_DISCOVERY_THREAD_NAME);
1137 if (IS_ERR(kthread)) {
Dean Nelson89eb8eb2005-03-23 19:50:00 -07001138 dev_err(xpc_part, "failed while forking discovery thread\n");
1139
1140 /* mark this new thread as a non-starter */
Jes Sorensenf9e505a2006-01-17 12:52:21 -05001141 complete(&xpc_discovery_exited);
Dean Nelson89eb8eb2005-03-23 19:50:00 -07001142
Dean Nelson65c17b82008-05-12 14:02:02 -07001143 xpc_do_exit(xpUnloading);
Dean Nelson89eb8eb2005-03-23 19:50:00 -07001144 return -EBUSY;
1145 }
1146
Dean Nelson89eb8eb2005-03-23 19:50:00 -07001147 /* set the interface to point at XPC's functions */
1148 xpc_set_interface(xpc_initiate_connect, xpc_initiate_disconnect,
Dean Nelson97bf1aa2008-07-29 22:34:08 -07001149 xpc_initiate_send, xpc_initiate_send_notify,
1150 xpc_initiate_received, xpc_initiate_partid_to_nasids);
Dean Nelson89eb8eb2005-03-23 19:50:00 -07001151
1152 return 0;
Dean Nelsonbc63d382008-07-29 22:34:04 -07001153
1154 /* initialization was not successful */
Dean Nelsonee6665e2008-07-29 22:34:13 -07001155out_3:
Dean Nelson81fe7882008-07-29 22:34:15 -07001156 /* a zero timestamp indicates our rsvd page is not initialized */
1157 xpc_rsvd_page->ts_jiffies = 0;
Dean Nelson94bd2702008-07-29 22:34:05 -07001158
Dean Nelsonbc63d382008-07-29 22:34:04 -07001159 (void)unregister_die_notifier(&xpc_die_notifier);
1160 (void)unregister_reboot_notifier(&xpc_reboot_notifier);
Dean Nelsonee6665e2008-07-29 22:34:13 -07001161out_2:
Dean Nelsonbc63d382008-07-29 22:34:04 -07001162 if (xpc_sysctl)
1163 unregister_sysctl_table(xpc_sysctl);
1164 kfree(xpc_partitions);
Dean Nelson6e410172008-07-29 22:34:09 -07001165out_1:
1166 if (is_shub())
1167 xpc_exit_sn2();
1168 else
1169 xpc_exit_uv();
Dean Nelsonbc63d382008-07-29 22:34:04 -07001170 return ret;
Dean Nelson89eb8eb2005-03-23 19:50:00 -07001171}
Dean Nelson89eb8eb2005-03-23 19:50:00 -07001172
Dean Nelson35190502008-04-22 14:48:55 -05001173module_init(xpc_init);
Dean Nelson89eb8eb2005-03-23 19:50:00 -07001174
1175void __exit
1176xpc_exit(void)
1177{
Dean Nelson65c17b82008-05-12 14:02:02 -07001178 xpc_do_exit(xpUnloading);
Dean Nelson89eb8eb2005-03-23 19:50:00 -07001179}
Dean Nelson89eb8eb2005-03-23 19:50:00 -07001180
Dean Nelson35190502008-04-22 14:48:55 -05001181module_exit(xpc_exit);
Dean Nelson89eb8eb2005-03-23 19:50:00 -07001182
1183MODULE_AUTHOR("Silicon Graphics, Inc.");
1184MODULE_DESCRIPTION("Cross Partition Communication (XPC) support");
1185MODULE_LICENSE("GPL");
1186
1187module_param(xpc_hb_interval, int, 0);
1188MODULE_PARM_DESC(xpc_hb_interval, "Number of seconds between "
Dean Nelson35190502008-04-22 14:48:55 -05001189 "heartbeat increments.");
Dean Nelson89eb8eb2005-03-23 19:50:00 -07001190
1191module_param(xpc_hb_check_interval, int, 0);
1192MODULE_PARM_DESC(xpc_hb_check_interval, "Number of seconds between "
Dean Nelson35190502008-04-22 14:48:55 -05001193 "heartbeat checks.");
Dean Nelson89eb8eb2005-03-23 19:50:00 -07001194
Dean Nelsona47d5da2008-07-29 22:34:09 -07001195module_param(xpc_disengage_timelimit, int, 0);
1196MODULE_PARM_DESC(xpc_disengage_timelimit, "Number of seconds to wait "
1197 "for disengage to complete.");
Dean Nelsone54af722005-10-25 14:07:43 -05001198
Dean Nelson1f4674b2006-01-10 11:08:00 -06001199module_param(xpc_kdebug_ignore, int, 0);
1200MODULE_PARM_DESC(xpc_kdebug_ignore, "Should lack of heartbeat be ignored by "
Dean Nelson35190502008-04-22 14:48:55 -05001201 "other partitions when dropping into kdebug.");