diff options
Diffstat (limited to 'arch/ia64/sn/kernel/xpc_main.c')
-rw-r--r-- | arch/ia64/sn/kernel/xpc_main.c | 189 |
1 files changed, 129 insertions, 60 deletions
diff --git a/arch/ia64/sn/kernel/xpc_main.c b/arch/ia64/sn/kernel/xpc_main.c index b617236524c6..8930586e0eb4 100644 --- a/arch/ia64/sn/kernel/xpc_main.c +++ b/arch/ia64/sn/kernel/xpc_main.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * License. See the file "COPYING" in the main directory of this archive | 3 | * License. See the file "COPYING" in the main directory of this archive |
4 | * for more details. | 4 | * for more details. |
5 | * | 5 | * |
6 | * Copyright (c) 2004-2005 Silicon Graphics, Inc. All Rights Reserved. | 6 | * Copyright (c) 2004-2006 Silicon Graphics, Inc. All Rights Reserved. |
7 | */ | 7 | */ |
8 | 8 | ||
9 | 9 | ||
@@ -59,7 +59,7 @@ | |||
59 | #include <asm/sn/sn_sal.h> | 59 | #include <asm/sn/sn_sal.h> |
60 | #include <asm/kdebug.h> | 60 | #include <asm/kdebug.h> |
61 | #include <asm/uaccess.h> | 61 | #include <asm/uaccess.h> |
62 | #include "xpc.h" | 62 | #include <asm/sn/xpc.h> |
63 | 63 | ||
64 | 64 | ||
65 | /* define two XPC debug device structures to be used with dev_dbg() et al */ | 65 | /* define two XPC debug device structures to be used with dev_dbg() et al */ |
@@ -82,6 +82,9 @@ struct device *xpc_part = &xpc_part_dbg_subname; | |||
82 | struct device *xpc_chan = &xpc_chan_dbg_subname; | 82 | struct device *xpc_chan = &xpc_chan_dbg_subname; |
83 | 83 | ||
84 | 84 | ||
85 | static int xpc_kdebug_ignore; | ||
86 | |||
87 | |||
85 | /* systune related variables for /proc/sys directories */ | 88 | /* systune related variables for /proc/sys directories */ |
86 | 89 | ||
87 | static int xpc_hb_interval = XPC_HB_DEFAULT_INTERVAL; | 90 | static int xpc_hb_interval = XPC_HB_DEFAULT_INTERVAL; |
@@ -162,6 +165,8 @@ static ctl_table xpc_sys_dir[] = { | |||
162 | }; | 165 | }; |
163 | static struct ctl_table_header *xpc_sysctl; | 166 | static struct ctl_table_header *xpc_sysctl; |
164 | 167 | ||
168 | /* non-zero if any remote partition disengage request was timed out */ | ||
169 | int xpc_disengage_request_timedout; | ||
165 | 170 | ||
166 | /* #of IRQs received */ | 171 | /* #of IRQs received */ |
167 | static atomic_t xpc_act_IRQ_rcvd; | 172 | static atomic_t xpc_act_IRQ_rcvd; |
@@ -773,7 +778,7 @@ xpc_daemonize_kthread(void *args) | |||
773 | ch->flags |= XPC_C_DISCONNECTCALLOUT; | 778 | ch->flags |= XPC_C_DISCONNECTCALLOUT; |
774 | spin_unlock_irqrestore(&ch->lock, irq_flags); | 779 | spin_unlock_irqrestore(&ch->lock, irq_flags); |
775 | 780 | ||
776 | xpc_disconnecting_callout(ch); | 781 | xpc_disconnect_callout(ch, xpcDisconnecting); |
777 | } else { | 782 | } else { |
778 | spin_unlock_irqrestore(&ch->lock, irq_flags); | 783 | spin_unlock_irqrestore(&ch->lock, irq_flags); |
779 | } | 784 | } |
@@ -921,9 +926,9 @@ static void | |||
921 | xpc_do_exit(enum xpc_retval reason) | 926 | xpc_do_exit(enum xpc_retval reason) |
922 | { | 927 | { |
923 | partid_t partid; | 928 | partid_t partid; |
924 | int active_part_count; | 929 | int active_part_count, printed_waiting_msg = 0; |
925 | struct xpc_partition *part; | 930 | struct xpc_partition *part; |
926 | unsigned long printmsg_time; | 931 | unsigned long printmsg_time, disengage_request_timeout = 0; |
927 | 932 | ||
928 | 933 | ||
929 | /* a 'rmmod XPC' and a 'reboot' cannot both end up here together */ | 934 | /* a 'rmmod XPC' and a 'reboot' cannot both end up here together */ |
@@ -953,7 +958,8 @@ xpc_do_exit(enum xpc_retval reason) | |||
953 | 958 | ||
954 | /* wait for all partitions to become inactive */ | 959 | /* wait for all partitions to become inactive */ |
955 | 960 | ||
956 | printmsg_time = jiffies; | 961 | printmsg_time = jiffies + (XPC_DISENGAGE_PRINTMSG_INTERVAL * HZ); |
962 | xpc_disengage_request_timedout = 0; | ||
957 | 963 | ||
958 | do { | 964 | do { |
959 | active_part_count = 0; | 965 | active_part_count = 0; |
@@ -969,20 +975,39 @@ xpc_do_exit(enum xpc_retval reason) | |||
969 | active_part_count++; | 975 | active_part_count++; |
970 | 976 | ||
971 | XPC_DEACTIVATE_PARTITION(part, reason); | 977 | XPC_DEACTIVATE_PARTITION(part, reason); |
972 | } | ||
973 | 978 | ||
974 | if (active_part_count == 0) { | 979 | if (part->disengage_request_timeout > |
975 | break; | 980 | disengage_request_timeout) { |
981 | disengage_request_timeout = | ||
982 | part->disengage_request_timeout; | ||
983 | } | ||
976 | } | 984 | } |
977 | 985 | ||
978 | if (jiffies >= printmsg_time) { | 986 | if (xpc_partition_engaged(-1UL)) { |
979 | dev_info(xpc_part, "waiting for partitions to " | 987 | if (time_after(jiffies, printmsg_time)) { |
980 | "deactivate/disengage, active count=%d, remote " | 988 | dev_info(xpc_part, "waiting for remote " |
981 | "engaged=0x%lx\n", active_part_count, | 989 | "partitions to disengage, timeout in " |
982 | xpc_partition_engaged(1UL << partid)); | 990 | "%ld seconds\n", |
983 | 991 | (disengage_request_timeout - jiffies) | |
984 | printmsg_time = jiffies + | 992 | / HZ); |
993 | printmsg_time = jiffies + | ||
985 | (XPC_DISENGAGE_PRINTMSG_INTERVAL * HZ); | 994 | (XPC_DISENGAGE_PRINTMSG_INTERVAL * HZ); |
995 | printed_waiting_msg = 1; | ||
996 | } | ||
997 | |||
998 | } else if (active_part_count > 0) { | ||
999 | if (printed_waiting_msg) { | ||
1000 | dev_info(xpc_part, "waiting for local partition" | ||
1001 | " to disengage\n"); | ||
1002 | printed_waiting_msg = 0; | ||
1003 | } | ||
1004 | |||
1005 | } else { | ||
1006 | if (!xpc_disengage_request_timedout) { | ||
1007 | dev_info(xpc_part, "all partitions have " | ||
1008 | "disengaged\n"); | ||
1009 | } | ||
1010 | break; | ||
986 | } | 1011 | } |
987 | 1012 | ||
988 | /* sleep for a 1/3 of a second or so */ | 1013 | /* sleep for a 1/3 of a second or so */ |
@@ -1000,11 +1025,13 @@ xpc_do_exit(enum xpc_retval reason) | |||
1000 | del_timer_sync(&xpc_hb_timer); | 1025 | del_timer_sync(&xpc_hb_timer); |
1001 | DBUG_ON(xpc_vars->heartbeating_to_mask != 0); | 1026 | DBUG_ON(xpc_vars->heartbeating_to_mask != 0); |
1002 | 1027 | ||
1003 | /* take ourselves off of the reboot_notifier_list */ | 1028 | if (reason == xpcUnloading) { |
1004 | (void) unregister_reboot_notifier(&xpc_reboot_notifier); | 1029 | /* take ourselves off of the reboot_notifier_list */ |
1030 | (void) unregister_reboot_notifier(&xpc_reboot_notifier); | ||
1005 | 1031 | ||
1006 | /* take ourselves off of the die_notifier list */ | 1032 | /* take ourselves off of the die_notifier list */ |
1007 | (void) unregister_die_notifier(&xpc_die_notifier); | 1033 | (void) unregister_die_notifier(&xpc_die_notifier); |
1034 | } | ||
1008 | 1035 | ||
1009 | /* close down protections for IPI operations */ | 1036 | /* close down protections for IPI operations */ |
1010 | xpc_restrict_IPI_ops(); | 1037 | xpc_restrict_IPI_ops(); |
@@ -1020,7 +1047,35 @@ xpc_do_exit(enum xpc_retval reason) | |||
1020 | 1047 | ||
1021 | 1048 | ||
1022 | /* | 1049 | /* |
1023 | * Called when the system is about to be either restarted or halted. | 1050 | * This function is called when the system is being rebooted. |
1051 | */ | ||
1052 | static int | ||
1053 | xpc_system_reboot(struct notifier_block *nb, unsigned long event, void *unused) | ||
1054 | { | ||
1055 | enum xpc_retval reason; | ||
1056 | |||
1057 | |||
1058 | switch (event) { | ||
1059 | case SYS_RESTART: | ||
1060 | reason = xpcSystemReboot; | ||
1061 | break; | ||
1062 | case SYS_HALT: | ||
1063 | reason = xpcSystemHalt; | ||
1064 | break; | ||
1065 | case SYS_POWER_OFF: | ||
1066 | reason = xpcSystemPoweroff; | ||
1067 | break; | ||
1068 | default: | ||
1069 | reason = xpcSystemGoingDown; | ||
1070 | } | ||
1071 | |||
1072 | xpc_do_exit(reason); | ||
1073 | return NOTIFY_DONE; | ||
1074 | } | ||
1075 | |||
1076 | |||
1077 | /* | ||
1078 | * Notify other partitions to disengage from all references to our memory. | ||
1024 | */ | 1079 | */ |
1025 | static void | 1080 | static void |
1026 | xpc_die_disengage(void) | 1081 | xpc_die_disengage(void) |
@@ -1028,7 +1083,7 @@ xpc_die_disengage(void) | |||
1028 | struct xpc_partition *part; | 1083 | struct xpc_partition *part; |
1029 | partid_t partid; | 1084 | partid_t partid; |
1030 | unsigned long engaged; | 1085 | unsigned long engaged; |
1031 | long time, print_time, disengage_request_timeout; | 1086 | long time, printmsg_time, disengage_request_timeout; |
1032 | 1087 | ||
1033 | 1088 | ||
1034 | /* keep xpc_hb_checker thread from doing anything (just in case) */ | 1089 | /* keep xpc_hb_checker thread from doing anything (just in case) */ |
@@ -1055,57 +1110,53 @@ xpc_die_disengage(void) | |||
1055 | } | 1110 | } |
1056 | } | 1111 | } |
1057 | 1112 | ||
1058 | print_time = rtc_time(); | 1113 | time = rtc_time(); |
1059 | disengage_request_timeout = print_time + | 1114 | printmsg_time = time + |
1115 | (XPC_DISENGAGE_PRINTMSG_INTERVAL * sn_rtc_cycles_per_second); | ||
1116 | disengage_request_timeout = time + | ||
1060 | (xpc_disengage_request_timelimit * sn_rtc_cycles_per_second); | 1117 | (xpc_disengage_request_timelimit * sn_rtc_cycles_per_second); |
1061 | 1118 | ||
1062 | /* wait for all other partitions to disengage from us */ | 1119 | /* wait for all other partitions to disengage from us */ |
1063 | 1120 | ||
1064 | while ((engaged = xpc_partition_engaged(-1UL)) && | 1121 | while (1) { |
1065 | (time = rtc_time()) < disengage_request_timeout) { | 1122 | engaged = xpc_partition_engaged(-1UL); |
1123 | if (!engaged) { | ||
1124 | dev_info(xpc_part, "all partitions have disengaged\n"); | ||
1125 | break; | ||
1126 | } | ||
1066 | 1127 | ||
1067 | if (time >= print_time) { | 1128 | time = rtc_time(); |
1129 | if (time >= disengage_request_timeout) { | ||
1130 | for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) { | ||
1131 | if (engaged & (1UL << partid)) { | ||
1132 | dev_info(xpc_part, "disengage from " | ||
1133 | "remote partition %d timed " | ||
1134 | "out\n", partid); | ||
1135 | } | ||
1136 | } | ||
1137 | break; | ||
1138 | } | ||
1139 | |||
1140 | if (time >= printmsg_time) { | ||
1068 | dev_info(xpc_part, "waiting for remote partitions to " | 1141 | dev_info(xpc_part, "waiting for remote partitions to " |
1069 | "disengage, engaged=0x%lx\n", engaged); | 1142 | "disengage, timeout in %ld seconds\n", |
1070 | print_time = time + (XPC_DISENGAGE_PRINTMSG_INTERVAL * | 1143 | (disengage_request_timeout - time) / |
1144 | sn_rtc_cycles_per_second); | ||
1145 | printmsg_time = time + | ||
1146 | (XPC_DISENGAGE_PRINTMSG_INTERVAL * | ||
1071 | sn_rtc_cycles_per_second); | 1147 | sn_rtc_cycles_per_second); |
1072 | } | 1148 | } |
1073 | } | 1149 | } |
1074 | dev_info(xpc_part, "finished waiting for remote partitions to " | ||
1075 | "disengage, engaged=0x%lx\n", engaged); | ||
1076 | } | ||
1077 | |||
1078 | |||
1079 | /* | ||
1080 | * This function is called when the system is being rebooted. | ||
1081 | */ | ||
1082 | static int | ||
1083 | xpc_system_reboot(struct notifier_block *nb, unsigned long event, void *unused) | ||
1084 | { | ||
1085 | enum xpc_retval reason; | ||
1086 | |||
1087 | |||
1088 | switch (event) { | ||
1089 | case SYS_RESTART: | ||
1090 | reason = xpcSystemReboot; | ||
1091 | break; | ||
1092 | case SYS_HALT: | ||
1093 | reason = xpcSystemHalt; | ||
1094 | break; | ||
1095 | case SYS_POWER_OFF: | ||
1096 | reason = xpcSystemPoweroff; | ||
1097 | break; | ||
1098 | default: | ||
1099 | reason = xpcSystemGoingDown; | ||
1100 | } | ||
1101 | |||
1102 | xpc_do_exit(reason); | ||
1103 | return NOTIFY_DONE; | ||
1104 | } | 1150 | } |
1105 | 1151 | ||
1106 | 1152 | ||
1107 | /* | 1153 | /* |
1108 | * This function is called when the system is being rebooted. | 1154 | * This function is called when the system is being restarted or halted due |
1155 | * to some sort of system failure. If this is the case we need to notify the | ||
1156 | * other partitions to disengage from all references to our memory. | ||
1157 | * This function can also be called when our heartbeater could be offlined | ||
1158 | * for a time. In this case we need to notify other partitions to not worry | ||
1159 | * about the lack of a heartbeat. | ||
1109 | */ | 1160 | */ |
1110 | static int | 1161 | static int |
1111 | xpc_system_die(struct notifier_block *nb, unsigned long event, void *unused) | 1162 | xpc_system_die(struct notifier_block *nb, unsigned long event, void *unused) |
@@ -1115,11 +1166,25 @@ xpc_system_die(struct notifier_block *nb, unsigned long event, void *unused) | |||
1115 | case DIE_MACHINE_HALT: | 1166 | case DIE_MACHINE_HALT: |
1116 | xpc_die_disengage(); | 1167 | xpc_die_disengage(); |
1117 | break; | 1168 | break; |
1169 | |||
1170 | case DIE_KDEBUG_ENTER: | ||
1171 | /* Should lack of heartbeat be ignored by other partitions? */ | ||
1172 | if (!xpc_kdebug_ignore) { | ||
1173 | break; | ||
1174 | } | ||
1175 | /* fall through */ | ||
1118 | case DIE_MCA_MONARCH_ENTER: | 1176 | case DIE_MCA_MONARCH_ENTER: |
1119 | case DIE_INIT_MONARCH_ENTER: | 1177 | case DIE_INIT_MONARCH_ENTER: |
1120 | xpc_vars->heartbeat++; | 1178 | xpc_vars->heartbeat++; |
1121 | xpc_vars->heartbeat_offline = 1; | 1179 | xpc_vars->heartbeat_offline = 1; |
1122 | break; | 1180 | break; |
1181 | |||
1182 | case DIE_KDEBUG_LEAVE: | ||
1183 | /* Is lack of heartbeat being ignored by other partitions? */ | ||
1184 | if (!xpc_kdebug_ignore) { | ||
1185 | break; | ||
1186 | } | ||
1187 | /* fall through */ | ||
1123 | case DIE_MCA_MONARCH_LEAVE: | 1188 | case DIE_MCA_MONARCH_LEAVE: |
1124 | case DIE_INIT_MONARCH_LEAVE: | 1189 | case DIE_INIT_MONARCH_LEAVE: |
1125 | xpc_vars->heartbeat++; | 1190 | xpc_vars->heartbeat++; |
@@ -1344,3 +1409,7 @@ module_param(xpc_disengage_request_timelimit, int, 0); | |||
1344 | MODULE_PARM_DESC(xpc_disengage_request_timelimit, "Number of seconds to wait " | 1409 | MODULE_PARM_DESC(xpc_disengage_request_timelimit, "Number of seconds to wait " |
1345 | "for disengage request to complete."); | 1410 | "for disengage request to complete."); |
1346 | 1411 | ||
1412 | module_param(xpc_kdebug_ignore, int, 0); | ||
1413 | MODULE_PARM_DESC(xpc_kdebug_ignore, "Should lack of heartbeat be ignored by " | ||
1414 | "other partitions when dropping into kdebug."); | ||
1415 | |||