Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux-2.6
[powerpc.git] / arch / ia64 / sn / kernel / xpc_main.c
index dcac286..8cbf164 100644 (file)
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (c) 2004-2005 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2004-2006 Silicon Graphics, Inc.  All Rights Reserved.
  */
 
 
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/reboot.h>
+#include <linux/completion.h>
 #include <asm/sn/intr.h>
 #include <asm/sn/sn_sal.h>
 #include <asm/kdebug.h>
 #include <asm/uaccess.h>
-#include "xpc.h"
+#include <asm/sn/xpc.h>
 
 
 /* define two XPC debug device structures to be used with dev_dbg() et al */
@@ -82,6 +83,9 @@ struct device *xpc_part = &xpc_part_dbg_subname;
 struct device *xpc_chan = &xpc_chan_dbg_subname;
 
 
+static int xpc_kdebug_ignore;
+
+
 /* systune related variables for /proc/sys directories */
 
 static int xpc_hb_interval = XPC_HB_DEFAULT_INTERVAL;
@@ -174,10 +178,10 @@ static DECLARE_WAIT_QUEUE_HEAD(xpc_act_IRQ_wq);
 static unsigned long xpc_hb_check_timeout;
 
 /* notification that the xpc_hb_checker thread has exited */
-static DECLARE_MUTEX_LOCKED(xpc_hb_checker_exited);
+static DECLARE_COMPLETION(xpc_hb_checker_exited);
 
 /* notification that the xpc_discovery thread has exited */
-static DECLARE_MUTEX_LOCKED(xpc_discovery_exited);
+static DECLARE_COMPLETION(xpc_discovery_exited);
 
 
 static struct timer_list xpc_hb_timer;
@@ -318,7 +322,7 @@ xpc_hb_checker(void *ignore)
 
 
        /* mark this thread as having exited */
-       up(&xpc_hb_checker_exited);
+       complete(&xpc_hb_checker_exited);
        return 0;
 }
 
@@ -338,7 +342,7 @@ xpc_initiate_discovery(void *ignore)
        dev_dbg(xpc_part, "discovery thread is exiting\n");
 
        /* mark this thread as having exited */
-       up(&xpc_discovery_exited);
+       complete(&xpc_discovery_exited);
        return 0;
 }
 
@@ -571,18 +575,21 @@ xpc_activate_partition(struct xpc_partition *part)
 
        spin_lock_irqsave(&part->act_lock, irq_flags);
 
-       pid = kernel_thread(xpc_activating, (void *) ((u64) partid), 0);
-
        DBUG_ON(part->act_state != XPC_P_INACTIVE);
 
-       if (pid > 0) {
-               part->act_state = XPC_P_ACTIVATION_REQ;
-               XPC_SET_REASON(part, xpcCloneKThread, __LINE__);
-       } else {
-               XPC_SET_REASON(part, xpcCloneKThreadFailed, __LINE__);
-       }
+       part->act_state = XPC_P_ACTIVATION_REQ;
+       XPC_SET_REASON(part, xpcCloneKThread, __LINE__);
 
        spin_unlock_irqrestore(&part->act_lock, irq_flags);
+
+       pid = kernel_thread(xpc_activating, (void *) ((u64) partid), 0);
+
+       if (unlikely(pid <= 0)) {
+               spin_lock_irqsave(&part->act_lock, irq_flags);
+               part->act_state = XPC_P_INACTIVE;
+               XPC_SET_REASON(part, xpcCloneKThreadFailed, __LINE__);
+               spin_unlock_irqrestore(&part->act_lock, irq_flags);
+       }
 }
 
 
@@ -743,12 +750,16 @@ xpc_daemonize_kthread(void *args)
                /* let registerer know that connection has been established */
 
                spin_lock_irqsave(&ch->lock, irq_flags);
-               if (!(ch->flags & XPC_C_CONNECTCALLOUT)) {
-                       ch->flags |= XPC_C_CONNECTCALLOUT;
+               if (!(ch->flags & XPC_C_CONNECTEDCALLOUT)) {
+                       ch->flags |= XPC_C_CONNECTEDCALLOUT;
                        spin_unlock_irqrestore(&ch->lock, irq_flags);
 
                        xpc_connected_callout(ch);
 
+                       spin_lock_irqsave(&ch->lock, irq_flags);
+                       ch->flags |= XPC_C_CONNECTEDCALLOUT_MADE;
+                       spin_unlock_irqrestore(&ch->lock, irq_flags);
+
                        /*
                         * It is possible that while the callout was being
                         * made that the remote partition sent some messages.
@@ -770,15 +781,17 @@ xpc_daemonize_kthread(void *args)
 
        if (atomic_dec_return(&ch->kthreads_assigned) == 0) {
                spin_lock_irqsave(&ch->lock, irq_flags);
-               if ((ch->flags & XPC_C_CONNECTCALLOUT) &&
-                               !(ch->flags & XPC_C_DISCONNECTCALLOUT)) {
-                       ch->flags |= XPC_C_DISCONNECTCALLOUT;
+               if ((ch->flags & XPC_C_CONNECTEDCALLOUT_MADE) &&
+                               !(ch->flags & XPC_C_DISCONNECTINGCALLOUT)) {
+                       ch->flags |= XPC_C_DISCONNECTINGCALLOUT;
                        spin_unlock_irqrestore(&ch->lock, irq_flags);
 
                        xpc_disconnect_callout(ch, xpcDisconnecting);
-               } else {
-                       spin_unlock_irqrestore(&ch->lock, irq_flags);
+
+                       spin_lock_irqsave(&ch->lock, irq_flags);
+                       ch->flags |= XPC_C_DISCONNECTINGCALLOUT_MADE;
                }
+               spin_unlock_irqrestore(&ch->lock, irq_flags);
                if (atomic_dec_return(&part->nchannels_engaged) == 0) {
                        xpc_mark_partition_disengaged(part);
                        xpc_IPI_send_disengage(part);
@@ -890,7 +903,7 @@ xpc_disconnect_wait(int ch_number)
                        continue;
                }
 
-               (void) down(&ch->wdisconnect_sema);
+               wait_for_completion(&ch->wdisconnect_wait);
 
                spin_lock_irqsave(&ch->lock, irq_flags);
                DBUG_ON(!(ch->flags & XPC_C_DISCONNECTED));
@@ -943,10 +956,10 @@ xpc_do_exit(enum xpc_retval reason)
        free_irq(SGI_XPC_ACTIVATE, NULL);
 
        /* wait for the discovery thread to exit */
-       down(&xpc_discovery_exited);
+       wait_for_completion(&xpc_discovery_exited);
 
        /* wait for the heartbeat checker thread to exit */
-       down(&xpc_hb_checker_exited);
+       wait_for_completion(&xpc_hb_checker_exited);
 
 
        /* sleep for a 1/3 of a second or so */
@@ -1044,7 +1057,35 @@ xpc_do_exit(enum xpc_retval reason)
 
 
 /*
- * Called when the system is about to be either restarted or halted.
+ * This function is called when the system is being rebooted.
+ */
+static int
+xpc_system_reboot(struct notifier_block *nb, unsigned long event, void *unused)
+{
+       enum xpc_retval reason;
+
+
+       switch (event) {
+       case SYS_RESTART:
+               reason = xpcSystemReboot;
+               break;
+       case SYS_HALT:
+               reason = xpcSystemHalt;
+               break;
+       case SYS_POWER_OFF:
+               reason = xpcSystemPoweroff;
+               break;
+       default:
+               reason = xpcSystemGoingDown;
+       }
+
+       xpc_do_exit(reason);
+       return NOTIFY_DONE;
+}
+
+
+/*
+ * Notify other partitions to disengage from all references to our memory.
  */
 static void
 xpc_die_disengage(void)
@@ -1120,35 +1161,12 @@ xpc_die_disengage(void)
 
 
 /*
- * This function is called when the system is being rebooted.
- */
-static int
-xpc_system_reboot(struct notifier_block *nb, unsigned long event, void *unused)
-{
-       enum xpc_retval reason;
-
-
-       switch (event) {
-       case SYS_RESTART:
-               reason = xpcSystemReboot;
-               break;
-       case SYS_HALT:
-               reason = xpcSystemHalt;
-               break;
-       case SYS_POWER_OFF:
-               reason = xpcSystemPoweroff;
-               break;
-       default:
-               reason = xpcSystemGoingDown;
-       }
-
-       xpc_do_exit(reason);
-       return NOTIFY_DONE;
-}
-
-
-/*
- * This function is called when the system is being rebooted.
+ * This function is called when the system is being restarted or halted due
+ * to some sort of system failure. If this is the case we need to notify the
+ * other partitions to disengage from all references to our memory.
+ * This function can also be called when our heartbeater could be offlined
+ * for a time. In this case we need to notify other partitions to not worry
+ * about the lack of a heartbeat.
  */
 static int
 xpc_system_die(struct notifier_block *nb, unsigned long event, void *unused)
@@ -1158,11 +1176,25 @@ xpc_system_die(struct notifier_block *nb, unsigned long event, void *unused)
        case DIE_MACHINE_HALT:
                xpc_die_disengage();
                break;
+
+       case DIE_KDEBUG_ENTER:
+               /* Should lack of heartbeat be ignored by other partitions? */
+               if (!xpc_kdebug_ignore) {
+                       break;
+               }
+               /* fall through */
        case DIE_MCA_MONARCH_ENTER:
        case DIE_INIT_MONARCH_ENTER:
                xpc_vars->heartbeat++;
                xpc_vars->heartbeat_offline = 1;
                break;
+
+       case DIE_KDEBUG_LEAVE:
+               /* Is lack of heartbeat being ignored by other partitions? */
+               if (!xpc_kdebug_ignore) {
+                       break;
+               }
+               /* fall through */
        case DIE_MCA_MONARCH_LEAVE:
        case DIE_INIT_MONARCH_LEAVE:
                xpc_vars->heartbeat++;
@@ -1345,7 +1377,7 @@ xpc_init(void)
                dev_err(xpc_part, "failed while forking discovery thread\n");
 
                /* mark this new thread as a non-starter */
-               up(&xpc_discovery_exited);
+               complete(&xpc_discovery_exited);
 
                xpc_do_exit(xpcUnloading);
                return -EBUSY;
@@ -1387,3 +1419,7 @@ module_param(xpc_disengage_request_timelimit, int, 0);
 MODULE_PARM_DESC(xpc_disengage_request_timelimit, "Number of seconds to wait "
                "for disengage request to complete.");
 
+module_param(xpc_kdebug_ignore, int, 0);
+MODULE_PARM_DESC(xpc_kdebug_ignore, "Should lack of heartbeat be ignored by "
+               "other partitions when dropping into kdebug.");
+