diff options
-rw-r--r-- | drivers/misc/sgi-xp/xpc.h | 14 | ||||
-rw-r--r-- | drivers/misc/sgi-xp/xpc_main.c | 96 | ||||
-rw-r--r-- | drivers/misc/sgi-xp/xpc_partition.c | 121 | ||||
-rw-r--r-- | drivers/misc/sgi-xp/xpc_sn2.c | 217 |
4 files changed, 229 insertions, 219 deletions
diff --git a/drivers/misc/sgi-xp/xpc.h b/drivers/misc/sgi-xp/xpc.h index 6b622b091bde..1edf37512de6 100644 --- a/drivers/misc/sgi-xp/xpc.h +++ b/drivers/misc/sgi-xp/xpc.h | |||
@@ -480,7 +480,7 @@ struct xpc_partition { | |||
480 | u64 remote_amos_page_pa; /* phys addr of partition's amos page */ | 480 | u64 remote_amos_page_pa; /* phys addr of partition's amos page */ |
481 | int remote_act_nasid; /* active part's act/deact nasid */ | 481 | int remote_act_nasid; /* active part's act/deact nasid */ |
482 | int remote_act_phys_cpuid; /* active part's act/deact phys cpuid */ | 482 | int remote_act_phys_cpuid; /* active part's act/deact phys cpuid */ |
483 | u32 act_IRQ_rcvd; /* IRQs since activation */ | 483 | u32 activate_IRQ_rcvd; /* IRQs since activation */ |
484 | spinlock_t act_lock; /* protect updating of act_state */ | 484 | spinlock_t act_lock; /* protect updating of act_state */ |
485 | u8 act_state; /* from XPC HB viewpoint */ | 485 | u8 act_state; /* from XPC HB viewpoint */ |
486 | u8 remote_vars_version; /* version# of partition's vars */ | 486 | u8 remote_vars_version; /* version# of partition's vars */ |
@@ -580,8 +580,8 @@ extern struct device *xpc_part; | |||
580 | extern struct device *xpc_chan; | 580 | extern struct device *xpc_chan; |
581 | extern int xpc_disengage_request_timelimit; | 581 | extern int xpc_disengage_request_timelimit; |
582 | extern int xpc_disengage_request_timedout; | 582 | extern int xpc_disengage_request_timedout; |
583 | extern atomic_t xpc_act_IRQ_rcvd; | 583 | extern atomic_t xpc_activate_IRQ_rcvd; |
584 | extern wait_queue_head_t xpc_act_IRQ_wq; | 584 | extern wait_queue_head_t xpc_activate_IRQ_wq; |
585 | extern void *xpc_heartbeating_to_mask; | 585 | extern void *xpc_heartbeating_to_mask; |
586 | extern irqreturn_t xpc_notify_IRQ_handler(int, void *); | 586 | extern irqreturn_t xpc_notify_IRQ_handler(int, void *); |
587 | extern void xpc_dropped_IPI_check(struct xpc_partition *); | 587 | extern void xpc_dropped_IPI_check(struct xpc_partition *); |
@@ -601,7 +601,7 @@ extern u64 (*xpc_get_IPI_flags) (struct xpc_partition *); | |||
601 | extern struct xpc_msg *(*xpc_get_deliverable_msg) (struct xpc_channel *); | 601 | extern struct xpc_msg *(*xpc_get_deliverable_msg) (struct xpc_channel *); |
602 | extern void (*xpc_initiate_partition_activation) (struct xpc_rsvd_page *, u64, | 602 | extern void (*xpc_initiate_partition_activation) (struct xpc_rsvd_page *, u64, |
603 | int); | 603 | int); |
604 | extern void (*xpc_process_act_IRQ_rcvd) (int); | 604 | extern void (*xpc_process_activate_IRQ_rcvd) (int); |
605 | extern enum xp_retval (*xpc_setup_infrastructure) (struct xpc_partition *); | 605 | extern enum xp_retval (*xpc_setup_infrastructure) (struct xpc_partition *); |
606 | extern void (*xpc_teardown_infrastructure) (struct xpc_partition *); | 606 | extern void (*xpc_teardown_infrastructure) (struct xpc_partition *); |
607 | extern void (*xpc_mark_partition_engaged) (struct xpc_partition *); | 607 | extern void (*xpc_mark_partition_engaged) (struct xpc_partition *); |
@@ -629,10 +629,12 @@ extern enum xp_retval (*xpc_send_msg) (struct xpc_channel *, u32, void *, u16, | |||
629 | extern void (*xpc_received_msg) (struct xpc_channel *, struct xpc_msg *); | 629 | extern void (*xpc_received_msg) (struct xpc_channel *, struct xpc_msg *); |
630 | 630 | ||
631 | /* found in xpc_sn2.c */ | 631 | /* found in xpc_sn2.c */ |
632 | extern void xpc_init_sn2(void); | 632 | extern int xpc_init_sn2(void); |
633 | extern void xpc_exit_sn2(void); | ||
633 | 634 | ||
634 | /* found in xpc_uv.c */ | 635 | /* found in xpc_uv.c */ |
635 | extern void xpc_init_uv(void); | 636 | extern void xpc_init_uv(void); |
637 | extern void xpc_exit_uv(void); | ||
636 | 638 | ||
637 | /* found in xpc_partition.c */ | 639 | /* found in xpc_partition.c */ |
638 | extern int xpc_exiting; | 640 | extern int xpc_exiting; |
@@ -646,7 +648,7 @@ extern void *xpc_kmalloc_cacheline_aligned(size_t, gfp_t, void **); | |||
646 | extern struct xpc_rsvd_page *xpc_setup_rsvd_page(void); | 648 | extern struct xpc_rsvd_page *xpc_setup_rsvd_page(void); |
647 | extern void xpc_allow_IPI_ops(void); | 649 | extern void xpc_allow_IPI_ops(void); |
648 | extern void xpc_restrict_IPI_ops(void); | 650 | extern void xpc_restrict_IPI_ops(void); |
649 | extern int xpc_identify_act_IRQ_sender(void); | 651 | extern int xpc_identify_activate_IRQ_sender(void); |
650 | extern int xpc_partition_disengaged(struct xpc_partition *); | 652 | extern int xpc_partition_disengaged(struct xpc_partition *); |
651 | extern enum xp_retval xpc_mark_partition_active(struct xpc_partition *); | 653 | extern enum xp_retval xpc_mark_partition_active(struct xpc_partition *); |
652 | extern void xpc_mark_partition_inactive(struct xpc_partition *); | 654 | extern void xpc_mark_partition_inactive(struct xpc_partition *); |
diff --git a/drivers/misc/sgi-xp/xpc_main.c b/drivers/misc/sgi-xp/xpc_main.c index aae90f5933b5..8780d5d00f62 100644 --- a/drivers/misc/sgi-xp/xpc_main.c +++ b/drivers/misc/sgi-xp/xpc_main.c | |||
@@ -147,11 +147,11 @@ static struct ctl_table_header *xpc_sysctl; | |||
147 | /* non-zero if any remote partition disengage request was timed out */ | 147 | /* non-zero if any remote partition disengage request was timed out */ |
148 | int xpc_disengage_request_timedout; | 148 | int xpc_disengage_request_timedout; |
149 | 149 | ||
150 | /* #of IRQs received */ | 150 | /* #of activate IRQs received */ |
151 | atomic_t xpc_act_IRQ_rcvd; | 151 | atomic_t xpc_activate_IRQ_rcvd = ATOMIC_INIT(0); |
152 | 152 | ||
153 | /* IRQ handler notifies this wait queue on receipt of an IRQ */ | 153 | /* IRQ handler notifies this wait queue on receipt of an IRQ */ |
154 | DECLARE_WAIT_QUEUE_HEAD(xpc_act_IRQ_wq); | 154 | DECLARE_WAIT_QUEUE_HEAD(xpc_activate_IRQ_wq); |
155 | 155 | ||
156 | static unsigned long xpc_hb_check_timeout; | 156 | static unsigned long xpc_hb_check_timeout; |
157 | static struct timer_list xpc_hb_timer; | 157 | static struct timer_list xpc_hb_timer; |
@@ -190,7 +190,7 @@ struct xpc_msg *(*xpc_get_deliverable_msg) (struct xpc_channel *ch); | |||
190 | void (*xpc_initiate_partition_activation) (struct xpc_rsvd_page *remote_rp, | 190 | void (*xpc_initiate_partition_activation) (struct xpc_rsvd_page *remote_rp, |
191 | u64 remote_rp_pa, int nasid); | 191 | u64 remote_rp_pa, int nasid); |
192 | 192 | ||
193 | void (*xpc_process_act_IRQ_rcvd) (int n_IRQs_expected); | 193 | void (*xpc_process_activate_IRQ_rcvd) (int n_IRQs_expected); |
194 | enum xp_retval (*xpc_setup_infrastructure) (struct xpc_partition *part); | 194 | enum xp_retval (*xpc_setup_infrastructure) (struct xpc_partition *part); |
195 | void (*xpc_teardown_infrastructure) (struct xpc_partition *part); | 195 | void (*xpc_teardown_infrastructure) (struct xpc_partition *part); |
196 | 196 | ||
@@ -239,17 +239,6 @@ xpc_timeout_partition_disengage_request(unsigned long data) | |||
239 | } | 239 | } |
240 | 240 | ||
241 | /* | 241 | /* |
242 | * Notify the heartbeat check thread that an IRQ has been received. | ||
243 | */ | ||
244 | static irqreturn_t | ||
245 | xpc_act_IRQ_handler(int irq, void *dev_id) | ||
246 | { | ||
247 | atomic_inc(&xpc_act_IRQ_rcvd); | ||
248 | wake_up_interruptible(&xpc_act_IRQ_wq); | ||
249 | return IRQ_HANDLED; | ||
250 | } | ||
251 | |||
252 | /* | ||
253 | * Timer to produce the heartbeat. The timer structures function is | 242 | * Timer to produce the heartbeat. The timer structures function is |
254 | * already set when this is initially called. A tunable is used to | 243 | * already set when this is initially called. A tunable is used to |
255 | * specify when the next timeout should occur. | 244 | * specify when the next timeout should occur. |
@@ -260,7 +249,7 @@ xpc_hb_beater(unsigned long dummy) | |||
260 | xpc_increment_heartbeat(); | 249 | xpc_increment_heartbeat(); |
261 | 250 | ||
262 | if (time_is_before_eq_jiffies(xpc_hb_check_timeout)) | 251 | if (time_is_before_eq_jiffies(xpc_hb_check_timeout)) |
263 | wake_up_interruptible(&xpc_act_IRQ_wq); | 252 | wake_up_interruptible(&xpc_activate_IRQ_wq); |
264 | 253 | ||
265 | xpc_hb_timer.expires = jiffies + (xpc_hb_interval * HZ); | 254 | xpc_hb_timer.expires = jiffies + (xpc_hb_interval * HZ); |
266 | add_timer(&xpc_hb_timer); | 255 | add_timer(&xpc_hb_timer); |
@@ -306,7 +295,7 @@ xpc_hb_checker(void *ignore) | |||
306 | dev_dbg(xpc_part, "woke up with %d ticks rem; %d IRQs have " | 295 | dev_dbg(xpc_part, "woke up with %d ticks rem; %d IRQs have " |
307 | "been received\n", | 296 | "been received\n", |
308 | (int)(xpc_hb_check_timeout - jiffies), | 297 | (int)(xpc_hb_check_timeout - jiffies), |
309 | atomic_read(&xpc_act_IRQ_rcvd) - last_IRQ_count); | 298 | atomic_read(&xpc_activate_IRQ_rcvd) - last_IRQ_count); |
310 | 299 | ||
311 | /* checking of remote heartbeats is skewed by IRQ handling */ | 300 | /* checking of remote heartbeats is skewed by IRQ handling */ |
312 | if (time_is_before_eq_jiffies(xpc_hb_check_timeout)) { | 301 | if (time_is_before_eq_jiffies(xpc_hb_check_timeout)) { |
@@ -322,15 +311,15 @@ xpc_hb_checker(void *ignore) | |||
322 | } | 311 | } |
323 | 312 | ||
324 | /* check for outstanding IRQs */ | 313 | /* check for outstanding IRQs */ |
325 | new_IRQ_count = atomic_read(&xpc_act_IRQ_rcvd); | 314 | new_IRQ_count = atomic_read(&xpc_activate_IRQ_rcvd); |
326 | if (last_IRQ_count < new_IRQ_count || force_IRQ != 0) { | 315 | if (last_IRQ_count < new_IRQ_count || force_IRQ != 0) { |
327 | force_IRQ = 0; | 316 | force_IRQ = 0; |
328 | 317 | ||
329 | dev_dbg(xpc_part, "found an IRQ to process; will be " | 318 | dev_dbg(xpc_part, "found an IRQ to process; will be " |
330 | "resetting xpc_hb_check_timeout\n"); | 319 | "resetting xpc_hb_check_timeout\n"); |
331 | 320 | ||
332 | xpc_process_act_IRQ_rcvd(new_IRQ_count - | 321 | xpc_process_activate_IRQ_rcvd(new_IRQ_count - |
333 | last_IRQ_count); | 322 | last_IRQ_count); |
334 | last_IRQ_count = new_IRQ_count; | 323 | last_IRQ_count = new_IRQ_count; |
335 | 324 | ||
336 | xpc_hb_check_timeout = jiffies + | 325 | xpc_hb_check_timeout = jiffies + |
@@ -338,9 +327,9 @@ xpc_hb_checker(void *ignore) | |||
338 | } | 327 | } |
339 | 328 | ||
340 | /* wait for IRQ or timeout */ | 329 | /* wait for IRQ or timeout */ |
341 | (void)wait_event_interruptible(xpc_act_IRQ_wq, | 330 | (void)wait_event_interruptible(xpc_activate_IRQ_wq, |
342 | (last_IRQ_count < | 331 | (last_IRQ_count < atomic_read( |
343 | atomic_read(&xpc_act_IRQ_rcvd) | 332 | &xpc_activate_IRQ_rcvd) |
344 | || time_is_before_eq_jiffies( | 333 | || time_is_before_eq_jiffies( |
345 | xpc_hb_check_timeout) || | 334 | xpc_hb_check_timeout) || |
346 | xpc_exiting)); | 335 | xpc_exiting)); |
@@ -884,10 +873,7 @@ xpc_do_exit(enum xp_retval reason) | |||
884 | * the heartbeat checker thread in case it's sleeping. | 873 | * the heartbeat checker thread in case it's sleeping. |
885 | */ | 874 | */ |
886 | xpc_exiting = 1; | 875 | xpc_exiting = 1; |
887 | wake_up_interruptible(&xpc_act_IRQ_wq); | 876 | wake_up_interruptible(&xpc_activate_IRQ_wq); |
888 | |||
889 | /* ignore all incoming interrupts */ | ||
890 | free_irq(SGI_XPC_ACTIVATE, NULL); | ||
891 | 877 | ||
892 | /* wait for the discovery thread to exit */ | 878 | /* wait for the discovery thread to exit */ |
893 | wait_for_completion(&xpc_discovery_exited); | 879 | wait_for_completion(&xpc_discovery_exited); |
@@ -968,9 +954,6 @@ xpc_do_exit(enum xp_retval reason) | |||
968 | (void)unregister_reboot_notifier(&xpc_reboot_notifier); | 954 | (void)unregister_reboot_notifier(&xpc_reboot_notifier); |
969 | } | 955 | } |
970 | 956 | ||
971 | /* close down protections for IPI operations */ | ||
972 | xpc_restrict_IPI_ops(); | ||
973 | |||
974 | /* clear the interface to XPC's functions */ | 957 | /* clear the interface to XPC's functions */ |
975 | xpc_clear_interface(); | 958 | xpc_clear_interface(); |
976 | 959 | ||
@@ -979,6 +962,11 @@ xpc_do_exit(enum xp_retval reason) | |||
979 | 962 | ||
980 | kfree(xpc_partitions); | 963 | kfree(xpc_partitions); |
981 | kfree(xpc_remote_copy_buffer_base); | 964 | kfree(xpc_remote_copy_buffer_base); |
965 | |||
966 | if (is_shub()) | ||
967 | xpc_exit_sn2(); | ||
968 | else | ||
969 | xpc_exit_uv(); | ||
982 | } | 970 | } |
983 | 971 | ||
984 | /* | 972 | /* |
@@ -1144,7 +1132,9 @@ xpc_init(void) | |||
1144 | if (xp_max_npartitions != 64) | 1132 | if (xp_max_npartitions != 64) |
1145 | return -EINVAL; | 1133 | return -EINVAL; |
1146 | 1134 | ||
1147 | xpc_init_sn2(); | 1135 | ret = xpc_init_sn2(); |
1136 | if (ret != 0) | ||
1137 | return ret; | ||
1148 | 1138 | ||
1149 | } else if (is_uv()) { | 1139 | } else if (is_uv()) { |
1150 | xpc_init_uv(); | 1140 | xpc_init_uv(); |
@@ -1163,7 +1153,8 @@ xpc_init(void) | |||
1163 | &xpc_remote_copy_buffer_base); | 1153 | &xpc_remote_copy_buffer_base); |
1164 | if (xpc_remote_copy_buffer == NULL) { | 1154 | if (xpc_remote_copy_buffer == NULL) { |
1165 | dev_err(xpc_part, "can't get memory for remote copy buffer\n"); | 1155 | dev_err(xpc_part, "can't get memory for remote copy buffer\n"); |
1166 | return -ENOMEM; | 1156 | ret = -ENOMEM; |
1157 | goto out_1; | ||
1167 | } | 1158 | } |
1168 | 1159 | ||
1169 | xpc_partitions = kzalloc(sizeof(struct xpc_partition) * | 1160 | xpc_partitions = kzalloc(sizeof(struct xpc_partition) * |
@@ -1171,7 +1162,7 @@ xpc_init(void) | |||
1171 | if (xpc_partitions == NULL) { | 1162 | if (xpc_partitions == NULL) { |
1172 | dev_err(xpc_part, "can't get memory for partition structure\n"); | 1163 | dev_err(xpc_part, "can't get memory for partition structure\n"); |
1173 | ret = -ENOMEM; | 1164 | ret = -ENOMEM; |
1174 | goto out_1; | 1165 | goto out_2; |
1175 | } | 1166 | } |
1176 | 1167 | ||
1177 | /* | 1168 | /* |
@@ -1187,7 +1178,7 @@ xpc_init(void) | |||
1187 | 1178 | ||
1188 | DBUG_ON((u64)part != L1_CACHE_ALIGN((u64)part)); | 1179 | DBUG_ON((u64)part != L1_CACHE_ALIGN((u64)part)); |
1189 | 1180 | ||
1190 | part->act_IRQ_rcvd = 0; | 1181 | part->activate_IRQ_rcvd = 0; |
1191 | spin_lock_init(&part->act_lock); | 1182 | spin_lock_init(&part->act_lock); |
1192 | part->act_state = XPC_P_INACTIVE; | 1183 | part->act_state = XPC_P_INACTIVE; |
1193 | XPC_SET_REASON(part, 0, 0); | 1184 | XPC_SET_REASON(part, 0, 0); |
@@ -1205,33 +1196,6 @@ xpc_init(void) | |||
1205 | xpc_sysctl = register_sysctl_table(xpc_sys_dir); | 1196 | xpc_sysctl = register_sysctl_table(xpc_sys_dir); |
1206 | 1197 | ||
1207 | /* | 1198 | /* |
1208 | * Open up protections for IPI operations (and AMO operations on | ||
1209 | * Shub 1.1 systems). | ||
1210 | */ | ||
1211 | xpc_allow_IPI_ops(); | ||
1212 | |||
1213 | /* | ||
1214 | * Interrupts being processed will increment this atomic variable and | ||
1215 | * awaken the heartbeat thread which will process the interrupts. | ||
1216 | */ | ||
1217 | atomic_set(&xpc_act_IRQ_rcvd, 0); | ||
1218 | |||
1219 | /* | ||
1220 | * This is safe to do before the xpc_hb_checker thread has started | ||
1221 | * because the handler releases a wait queue. If an interrupt is | ||
1222 | * received before the thread is waiting, it will not go to sleep, | ||
1223 | * but rather immediately process the interrupt. | ||
1224 | */ | ||
1225 | ret = request_irq(SGI_XPC_ACTIVATE, xpc_act_IRQ_handler, 0, | ||
1226 | "xpc hb", NULL); | ||
1227 | if (ret != 0) { | ||
1228 | dev_err(xpc_part, "can't register ACTIVATE IRQ handler, " | ||
1229 | "errno=%d\n", -ret); | ||
1230 | ret = -EBUSY; | ||
1231 | goto out_2; | ||
1232 | } | ||
1233 | |||
1234 | /* | ||
1235 | * Fill the partition reserved page with the information needed by | 1199 | * Fill the partition reserved page with the information needed by |
1236 | * other partitions to discover we are alive and establish initial | 1200 | * other partitions to discover we are alive and establish initial |
1237 | * communications. | 1201 | * communications. |
@@ -1296,14 +1260,16 @@ out_4: | |||
1296 | (void)unregister_die_notifier(&xpc_die_notifier); | 1260 | (void)unregister_die_notifier(&xpc_die_notifier); |
1297 | (void)unregister_reboot_notifier(&xpc_reboot_notifier); | 1261 | (void)unregister_reboot_notifier(&xpc_reboot_notifier); |
1298 | out_3: | 1262 | out_3: |
1299 | free_irq(SGI_XPC_ACTIVATE, NULL); | ||
1300 | out_2: | ||
1301 | xpc_restrict_IPI_ops(); | ||
1302 | if (xpc_sysctl) | 1263 | if (xpc_sysctl) |
1303 | unregister_sysctl_table(xpc_sysctl); | 1264 | unregister_sysctl_table(xpc_sysctl); |
1304 | kfree(xpc_partitions); | 1265 | kfree(xpc_partitions); |
1305 | out_1: | 1266 | out_2: |
1306 | kfree(xpc_remote_copy_buffer_base); | 1267 | kfree(xpc_remote_copy_buffer_base); |
1268 | out_1: | ||
1269 | if (is_shub()) | ||
1270 | xpc_exit_sn2(); | ||
1271 | else | ||
1272 | xpc_exit_uv(); | ||
1307 | return ret; | 1273 | return ret; |
1308 | } | 1274 | } |
1309 | 1275 | ||
diff --git a/drivers/misc/sgi-xp/xpc_partition.c b/drivers/misc/sgi-xp/xpc_partition.c index 90ec5ca8c9ab..bf9b1193bd2a 100644 --- a/drivers/misc/sgi-xp/xpc_partition.c +++ b/drivers/misc/sgi-xp/xpc_partition.c | |||
@@ -29,16 +29,6 @@ | |||
29 | /* XPC is exiting flag */ | 29 | /* XPC is exiting flag */ |
30 | int xpc_exiting; | 30 | int xpc_exiting; |
31 | 31 | ||
32 | /* SH_IPI_ACCESS shub register value on startup */ | ||
33 | static u64 xpc_sh1_IPI_access; | ||
34 | static u64 xpc_sh2_IPI_access0; | ||
35 | static u64 xpc_sh2_IPI_access1; | ||
36 | static u64 xpc_sh2_IPI_access2; | ||
37 | static u64 xpc_sh2_IPI_access3; | ||
38 | |||
39 | /* original protection values for each node */ | ||
40 | u64 xpc_prot_vec[MAX_NUMNODES]; | ||
41 | |||
42 | /* this partition's reserved page pointers */ | 32 | /* this partition's reserved page pointers */ |
43 | struct xpc_rsvd_page *xpc_rsvd_page; | 33 | struct xpc_rsvd_page *xpc_rsvd_page; |
44 | static u64 *xpc_part_nasids; | 34 | static u64 *xpc_part_nasids; |
@@ -211,117 +201,6 @@ xpc_setup_rsvd_page(void) | |||
211 | } | 201 | } |
212 | 202 | ||
213 | /* | 203 | /* |
214 | * Change protections to allow IPI operations (and AMO operations on | ||
215 | * Shub 1.1 systems). | ||
216 | */ | ||
217 | void | ||
218 | xpc_allow_IPI_ops(void) | ||
219 | { | ||
220 | int node; | ||
221 | int nasid; | ||
222 | |||
223 | /* >>> Change SH_IPI_ACCESS code to use SAL call once it is available */ | ||
224 | |||
225 | if (is_shub2()) { | ||
226 | xpc_sh2_IPI_access0 = | ||
227 | (u64)HUB_L((u64 *)LOCAL_MMR_ADDR(SH2_IPI_ACCESS0)); | ||
228 | xpc_sh2_IPI_access1 = | ||
229 | (u64)HUB_L((u64 *)LOCAL_MMR_ADDR(SH2_IPI_ACCESS1)); | ||
230 | xpc_sh2_IPI_access2 = | ||
231 | (u64)HUB_L((u64 *)LOCAL_MMR_ADDR(SH2_IPI_ACCESS2)); | ||
232 | xpc_sh2_IPI_access3 = | ||
233 | (u64)HUB_L((u64 *)LOCAL_MMR_ADDR(SH2_IPI_ACCESS3)); | ||
234 | |||
235 | for_each_online_node(node) { | ||
236 | nasid = cnodeid_to_nasid(node); | ||
237 | HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS0), | ||
238 | -1UL); | ||
239 | HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS1), | ||
240 | -1UL); | ||
241 | HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS2), | ||
242 | -1UL); | ||
243 | HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS3), | ||
244 | -1UL); | ||
245 | } | ||
246 | |||
247 | } else { | ||
248 | xpc_sh1_IPI_access = | ||
249 | (u64)HUB_L((u64 *)LOCAL_MMR_ADDR(SH1_IPI_ACCESS)); | ||
250 | |||
251 | for_each_online_node(node) { | ||
252 | nasid = cnodeid_to_nasid(node); | ||
253 | HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH1_IPI_ACCESS), | ||
254 | -1UL); | ||
255 | |||
256 | /* | ||
257 | * Since the BIST collides with memory operations on | ||
258 | * SHUB 1.1 sn_change_memprotect() cannot be used. | ||
259 | */ | ||
260 | if (enable_shub_wars_1_1()) { | ||
261 | /* open up everything */ | ||
262 | xpc_prot_vec[node] = (u64)HUB_L((u64 *) | ||
263 | GLOBAL_MMR_ADDR | ||
264 | (nasid, | ||
265 | SH1_MD_DQLP_MMR_DIR_PRIVEC0)); | ||
266 | HUB_S((u64 *) | ||
267 | GLOBAL_MMR_ADDR(nasid, | ||
268 | SH1_MD_DQLP_MMR_DIR_PRIVEC0), | ||
269 | -1UL); | ||
270 | HUB_S((u64 *) | ||
271 | GLOBAL_MMR_ADDR(nasid, | ||
272 | SH1_MD_DQRP_MMR_DIR_PRIVEC0), | ||
273 | -1UL); | ||
274 | } | ||
275 | } | ||
276 | } | ||
277 | } | ||
278 | |||
279 | /* | ||
280 | * Restrict protections to disallow IPI operations (and AMO operations on | ||
281 | * Shub 1.1 systems). | ||
282 | */ | ||
283 | void | ||
284 | xpc_restrict_IPI_ops(void) | ||
285 | { | ||
286 | int node; | ||
287 | int nasid; | ||
288 | |||
289 | /* >>> Change SH_IPI_ACCESS code to use SAL call once it is available */ | ||
290 | |||
291 | if (is_shub2()) { | ||
292 | |||
293 | for_each_online_node(node) { | ||
294 | nasid = cnodeid_to_nasid(node); | ||
295 | HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS0), | ||
296 | xpc_sh2_IPI_access0); | ||
297 | HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS1), | ||
298 | xpc_sh2_IPI_access1); | ||
299 | HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS2), | ||
300 | xpc_sh2_IPI_access2); | ||
301 | HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS3), | ||
302 | xpc_sh2_IPI_access3); | ||
303 | } | ||
304 | |||
305 | } else { | ||
306 | |||
307 | for_each_online_node(node) { | ||
308 | nasid = cnodeid_to_nasid(node); | ||
309 | HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH1_IPI_ACCESS), | ||
310 | xpc_sh1_IPI_access); | ||
311 | |||
312 | if (enable_shub_wars_1_1()) { | ||
313 | HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, | ||
314 | SH1_MD_DQLP_MMR_DIR_PRIVEC0), | ||
315 | xpc_prot_vec[node]); | ||
316 | HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, | ||
317 | SH1_MD_DQRP_MMR_DIR_PRIVEC0), | ||
318 | xpc_prot_vec[node]); | ||
319 | } | ||
320 | } | ||
321 | } | ||
322 | } | ||
323 | |||
324 | /* | ||
325 | * Get a copy of a portion of the remote partition's rsvd page. | 204 | * Get a copy of a portion of the remote partition's rsvd page. |
326 | * | 205 | * |
327 | * remote_rp points to a buffer that is cacheline aligned for BTE copies and | 206 | * remote_rp points to a buffer that is cacheline aligned for BTE copies and |
diff --git a/drivers/misc/sgi-xp/xpc_sn2.c b/drivers/misc/sgi-xp/xpc_sn2.c index db67d348b35c..4659f6cb885e 100644 --- a/drivers/misc/sgi-xp/xpc_sn2.c +++ b/drivers/misc/sgi-xp/xpc_sn2.c | |||
@@ -22,6 +22,87 @@ | |||
22 | static struct xpc_vars_sn2 *xpc_vars; /* >>> Add _sn2 suffix? */ | 22 | static struct xpc_vars_sn2 *xpc_vars; /* >>> Add _sn2 suffix? */ |
23 | static struct xpc_vars_part_sn2 *xpc_vars_part; /* >>> Add _sn2 suffix? */ | 23 | static struct xpc_vars_part_sn2 *xpc_vars_part; /* >>> Add _sn2 suffix? */ |
24 | 24 | ||
25 | /* SH_IPI_ACCESS shub register value on startup */ | ||
26 | static u64 xpc_sh1_IPI_access; | ||
27 | static u64 xpc_sh2_IPI_access0; | ||
28 | static u64 xpc_sh2_IPI_access1; | ||
29 | static u64 xpc_sh2_IPI_access2; | ||
30 | static u64 xpc_sh2_IPI_access3; | ||
31 | |||
32 | /* | ||
33 | * Change protections to allow IPI operations. | ||
34 | */ | ||
35 | static void | ||
36 | xpc_allow_IPI_ops_sn2(void) | ||
37 | { | ||
38 | int node; | ||
39 | int nasid; | ||
40 | |||
41 | /* >>> The following should get moved into SAL. */ | ||
42 | if (is_shub2()) { | ||
43 | xpc_sh2_IPI_access0 = | ||
44 | (u64)HUB_L((u64 *)LOCAL_MMR_ADDR(SH2_IPI_ACCESS0)); | ||
45 | xpc_sh2_IPI_access1 = | ||
46 | (u64)HUB_L((u64 *)LOCAL_MMR_ADDR(SH2_IPI_ACCESS1)); | ||
47 | xpc_sh2_IPI_access2 = | ||
48 | (u64)HUB_L((u64 *)LOCAL_MMR_ADDR(SH2_IPI_ACCESS2)); | ||
49 | xpc_sh2_IPI_access3 = | ||
50 | (u64)HUB_L((u64 *)LOCAL_MMR_ADDR(SH2_IPI_ACCESS3)); | ||
51 | |||
52 | for_each_online_node(node) { | ||
53 | nasid = cnodeid_to_nasid(node); | ||
54 | HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS0), | ||
55 | -1UL); | ||
56 | HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS1), | ||
57 | -1UL); | ||
58 | HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS2), | ||
59 | -1UL); | ||
60 | HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS3), | ||
61 | -1UL); | ||
62 | } | ||
63 | } else { | ||
64 | xpc_sh1_IPI_access = | ||
65 | (u64)HUB_L((u64 *)LOCAL_MMR_ADDR(SH1_IPI_ACCESS)); | ||
66 | |||
67 | for_each_online_node(node) { | ||
68 | nasid = cnodeid_to_nasid(node); | ||
69 | HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH1_IPI_ACCESS), | ||
70 | -1UL); | ||
71 | } | ||
72 | } | ||
73 | } | ||
74 | |||
75 | /* | ||
76 | * Restrict protections to disallow IPI operations. | ||
77 | */ | ||
78 | static void | ||
79 | xpc_disallow_IPI_ops_sn2(void) | ||
80 | { | ||
81 | int node; | ||
82 | int nasid; | ||
83 | |||
84 | /* >>> The following should get moved into SAL. */ | ||
85 | if (is_shub2()) { | ||
86 | for_each_online_node(node) { | ||
87 | nasid = cnodeid_to_nasid(node); | ||
88 | HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS0), | ||
89 | xpc_sh2_IPI_access0); | ||
90 | HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS1), | ||
91 | xpc_sh2_IPI_access1); | ||
92 | HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS2), | ||
93 | xpc_sh2_IPI_access2); | ||
94 | HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS3), | ||
95 | xpc_sh2_IPI_access3); | ||
96 | } | ||
97 | } else { | ||
98 | for_each_online_node(node) { | ||
99 | nasid = cnodeid_to_nasid(node); | ||
100 | HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH1_IPI_ACCESS), | ||
101 | xpc_sh1_IPI_access); | ||
102 | } | ||
103 | } | ||
104 | } | ||
105 | |||
25 | /* | 106 | /* |
26 | * The following set of macros and functions are used for the sending and | 107 | * The following set of macros and functions are used for the sending and |
27 | * receiving of IPIs (also known as IRQs). There are two flavors of IPIs, | 108 | * receiving of IPIs (also known as IRQs). There are two flavors of IPIs, |
@@ -74,6 +155,17 @@ xpc_IPI_init_sn2(int index) | |||
74 | */ | 155 | */ |
75 | 156 | ||
76 | /* | 157 | /* |
158 | * Notify the heartbeat check thread that an activate IRQ has been received. | ||
159 | */ | ||
160 | static irqreturn_t | ||
161 | xpc_handle_activate_IRQ_sn2(int irq, void *dev_id) | ||
162 | { | ||
163 | atomic_inc(&xpc_activate_IRQ_rcvd); | ||
164 | wake_up_interruptible(&xpc_activate_IRQ_wq); | ||
165 | return IRQ_HANDLED; | ||
166 | } | ||
167 | |||
168 | /* | ||
77 | * Flag the appropriate AMO variable and send an IPI to the specified node. | 169 | * Flag the appropriate AMO variable and send an IPI to the specified node. |
78 | */ | 170 | */ |
79 | static void | 171 | static void |
@@ -100,8 +192,8 @@ xpc_activate_IRQ_send_local_sn2(int from_nasid) | |||
100 | /* fake the sending and receipt of an activate IRQ from remote nasid */ | 192 | /* fake the sending and receipt of an activate IRQ from remote nasid */ |
101 | FETCHOP_STORE_OP(TO_AMO((u64)&amos[w_index].variable), FETCHOP_OR, | 193 | FETCHOP_STORE_OP(TO_AMO((u64)&amos[w_index].variable), FETCHOP_OR, |
102 | (1UL << b_index)); | 194 | (1UL << b_index)); |
103 | atomic_inc(&xpc_act_IRQ_rcvd); | 195 | atomic_inc(&xpc_activate_IRQ_rcvd); |
104 | wake_up_interruptible(&xpc_act_IRQ_wq); | 196 | wake_up_interruptible(&xpc_activate_IRQ_wq); |
105 | } | 197 | } |
106 | 198 | ||
107 | static void | 199 | static void |
@@ -383,11 +475,65 @@ xpc_clear_partition_disengage_request_sn2(u64 partid_mask) | |||
383 | ~partid_mask); | 475 | ~partid_mask); |
384 | } | 476 | } |
385 | 477 | ||
478 | /* original protection values for each node */ | ||
479 | static u64 xpc_prot_vec_sn2[MAX_NUMNODES]; | ||
480 | |||
481 | /* | ||
482 | * Change protections to allow AMO operations on non-Shub 1.1 systems. | ||
483 | */ | ||
484 | static enum xp_retval | ||
485 | xpc_allow_AMO_ops_sn2(AMO_t *amos_page) | ||
486 | { | ||
487 | u64 nasid_array = 0; | ||
488 | int ret; | ||
489 | |||
490 | /* | ||
491 | * On SHUB 1.1, we cannot call sn_change_memprotect() since the BIST | ||
492 | * collides with memory operations. On those systems we call | ||
493 | * xpc_allow_AMO_ops_shub_wars_1_1_sn2() instead. | ||
494 | */ | ||
495 | if (!enable_shub_wars_1_1()) { | ||
496 | ret = sn_change_memprotect(ia64_tpa((u64)amos_page), PAGE_SIZE, | ||
497 | SN_MEMPROT_ACCESS_CLASS_1, | ||
498 | &nasid_array); | ||
499 | if (ret != 0) | ||
500 | return xpSalError; | ||
501 | } | ||
502 | return xpSuccess; | ||
503 | } | ||
504 | |||
505 | /* | ||
506 | * Change protections to allow AMO operations on Shub 1.1 systems. | ||
507 | */ | ||
508 | static void | ||
509 | xpc_allow_AMO_ops_shub_wars_1_1_sn2(void) | ||
510 | { | ||
511 | int node; | ||
512 | int nasid; | ||
513 | |||
514 | if (!enable_shub_wars_1_1()) | ||
515 | return; | ||
516 | |||
517 | for_each_online_node(node) { | ||
518 | nasid = cnodeid_to_nasid(node); | ||
519 | /* save current protection values */ | ||
520 | xpc_prot_vec_sn2[node] = | ||
521 | (u64)HUB_L((u64 *)GLOBAL_MMR_ADDR(nasid, | ||
522 | SH1_MD_DQLP_MMR_DIR_PRIVEC0)); | ||
523 | /* open up everything */ | ||
524 | HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, | ||
525 | SH1_MD_DQLP_MMR_DIR_PRIVEC0), | ||
526 | -1UL); | ||
527 | HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, | ||
528 | SH1_MD_DQRP_MMR_DIR_PRIVEC0), | ||
529 | -1UL); | ||
530 | } | ||
531 | } | ||
532 | |||
386 | static enum xp_retval | 533 | static enum xp_retval |
387 | xpc_rsvd_page_init_sn2(struct xpc_rsvd_page *rp) | 534 | xpc_rsvd_page_init_sn2(struct xpc_rsvd_page *rp) |
388 | { | 535 | { |
389 | AMO_t *amos_page; | 536 | AMO_t *amos_page; |
390 | u64 nasid_array = 0; | ||
391 | int i; | 537 | int i; |
392 | int ret; | 538 | int ret; |
393 | 539 | ||
@@ -421,21 +567,15 @@ xpc_rsvd_page_init_sn2(struct xpc_rsvd_page *rp) | |||
421 | } | 567 | } |
422 | 568 | ||
423 | /* | 569 | /* |
424 | * Open up AMO-R/W to cpu. This is done for Shub 1.1 systems | 570 | * Open up AMO-R/W to cpu. This is done on Shub 1.1 systems |
425 | * when xpc_allow_IPI_ops() is called via xpc_hb_init(). | 571 | * when xpc_allow_AMO_ops_shub_wars_1_1_sn2() is called. |
426 | */ | 572 | */ |
427 | if (!enable_shub_wars_1_1()) { | 573 | ret = xpc_allow_AMO_ops_sn2(amos_page); |
428 | ret = sn_change_memprotect(ia64_tpa((u64)amos_page), | 574 | if (ret != xpSuccess) { |
429 | PAGE_SIZE, | 575 | dev_err(xpc_part, "can't allow AMO operations\n"); |
430 | SN_MEMPROT_ACCESS_CLASS_1, | 576 | uncached_free_page(__IA64_UNCACHED_OFFSET | |
431 | &nasid_array); | 577 | TO_PHYS((u64)amos_page), 1); |
432 | if (ret != 0) { | 578 | return ret; |
433 | dev_err(xpc_part, "can't change memory " | ||
434 | "protections\n"); | ||
435 | uncached_free_page(__IA64_UNCACHED_OFFSET | | ||
436 | TO_PHYS((u64)amos_page), 1); | ||
437 | return xpSalError; | ||
438 | } | ||
439 | } | 579 | } |
440 | } | 580 | } |
441 | 581 | ||
@@ -656,7 +796,7 @@ xpc_update_partition_info_sn2(struct xpc_partition *part, u8 remote_rp_version, | |||
656 | * initialized reserved page. | 796 | * initialized reserved page. |
657 | */ | 797 | */ |
658 | static void | 798 | static void |
659 | xpc_identify_act_IRQ_req_sn2(int nasid) | 799 | xpc_identify_activate_IRQ_req_sn2(int nasid) |
660 | { | 800 | { |
661 | struct xpc_rsvd_page *remote_rp; | 801 | struct xpc_rsvd_page *remote_rp; |
662 | struct xpc_vars_sn2 *remote_vars; | 802 | struct xpc_vars_sn2 *remote_vars; |
@@ -702,10 +842,10 @@ xpc_identify_act_IRQ_req_sn2(int nasid) | |||
702 | return; | 842 | return; |
703 | } | 843 | } |
704 | 844 | ||
705 | part->act_IRQ_rcvd++; | 845 | part->activate_IRQ_rcvd++; |
706 | 846 | ||
707 | dev_dbg(xpc_part, "partid for nasid %d is %d; IRQs = %d; HB = " | 847 | dev_dbg(xpc_part, "partid for nasid %d is %d; IRQs = %d; HB = " |
708 | "%ld:0x%lx\n", (int)nasid, (int)partid, part->act_IRQ_rcvd, | 848 | "%ld:0x%lx\n", (int)nasid, (int)partid, part->activate_IRQ_rcvd, |
709 | remote_vars->heartbeat, remote_vars->heartbeating_to_mask[0]); | 849 | remote_vars->heartbeat, remote_vars->heartbeating_to_mask[0]); |
710 | 850 | ||
711 | if (xpc_partition_disengaged(part) && | 851 | if (xpc_partition_disengaged(part) && |
@@ -831,7 +971,7 @@ xpc_identify_act_IRQ_req_sn2(int nasid) | |||
831 | * Return #of IRQs detected. | 971 | * Return #of IRQs detected. |
832 | */ | 972 | */ |
833 | int | 973 | int |
834 | xpc_identify_act_IRQ_sender_sn2(void) | 974 | xpc_identify_activate_IRQ_sender_sn2(void) |
835 | { | 975 | { |
836 | int word, bit; | 976 | int word, bit; |
837 | u64 nasid_mask; | 977 | u64 nasid_mask; |
@@ -872,7 +1012,7 @@ xpc_identify_act_IRQ_sender_sn2(void) | |||
872 | nasid = XPC_NASID_FROM_W_B(word, bit); | 1012 | nasid = XPC_NASID_FROM_W_B(word, bit); |
873 | dev_dbg(xpc_part, "interrupt from nasid %ld\n", | 1013 | dev_dbg(xpc_part, "interrupt from nasid %ld\n", |
874 | nasid); | 1014 | nasid); |
875 | xpc_identify_act_IRQ_req_sn2(nasid); | 1015 | xpc_identify_activate_IRQ_req_sn2(nasid); |
876 | } | 1016 | } |
877 | } | 1017 | } |
878 | } | 1018 | } |
@@ -880,14 +1020,14 @@ xpc_identify_act_IRQ_sender_sn2(void) | |||
880 | } | 1020 | } |
881 | 1021 | ||
882 | static void | 1022 | static void |
883 | xpc_process_act_IRQ_rcvd_sn2(int n_IRQs_expected) | 1023 | xpc_process_activate_IRQ_rcvd_sn2(int n_IRQs_expected) |
884 | { | 1024 | { |
885 | int n_IRQs_detected; | 1025 | int n_IRQs_detected; |
886 | 1026 | ||
887 | n_IRQs_detected = xpc_identify_act_IRQ_sender_sn2(); | 1027 | n_IRQs_detected = xpc_identify_activate_IRQ_sender_sn2(); |
888 | if (n_IRQs_detected < n_IRQs_expected) { | 1028 | if (n_IRQs_detected < n_IRQs_expected) { |
889 | /* retry once to help avoid missing AMO */ | 1029 | /* retry once to help avoid missing AMO */ |
890 | (void)xpc_identify_act_IRQ_sender_sn2(); | 1030 | (void)xpc_identify_activate_IRQ_sender_sn2(); |
891 | } | 1031 | } |
892 | } | 1032 | } |
893 | 1033 | ||
@@ -1775,9 +1915,11 @@ xpc_received_msg_sn2(struct xpc_channel *ch, struct xpc_msg *msg) | |||
1775 | xpc_acknowledge_msgs_sn2(ch, get, msg->flags); | 1915 | xpc_acknowledge_msgs_sn2(ch, get, msg->flags); |
1776 | } | 1916 | } |
1777 | 1917 | ||
1778 | void | 1918 | int |
1779 | xpc_init_sn2(void) | 1919 | xpc_init_sn2(void) |
1780 | { | 1920 | { |
1921 | int ret; | ||
1922 | |||
1781 | xpc_rsvd_page_init = xpc_rsvd_page_init_sn2; | 1923 | xpc_rsvd_page_init = xpc_rsvd_page_init_sn2; |
1782 | xpc_increment_heartbeat = xpc_increment_heartbeat_sn2; | 1924 | xpc_increment_heartbeat = xpc_increment_heartbeat_sn2; |
1783 | xpc_offline_heartbeat = xpc_offline_heartbeat_sn2; | 1925 | xpc_offline_heartbeat = xpc_offline_heartbeat_sn2; |
@@ -1788,7 +1930,7 @@ xpc_init_sn2(void) | |||
1788 | 1930 | ||
1789 | xpc_initiate_partition_activation = | 1931 | xpc_initiate_partition_activation = |
1790 | xpc_initiate_partition_activation_sn2; | 1932 | xpc_initiate_partition_activation_sn2; |
1791 | xpc_process_act_IRQ_rcvd = xpc_process_act_IRQ_rcvd_sn2; | 1933 | xpc_process_activate_IRQ_rcvd = xpc_process_activate_IRQ_rcvd_sn2; |
1792 | xpc_setup_infrastructure = xpc_setup_infrastructure_sn2; | 1934 | xpc_setup_infrastructure = xpc_setup_infrastructure_sn2; |
1793 | xpc_teardown_infrastructure = xpc_teardown_infrastructure_sn2; | 1935 | xpc_teardown_infrastructure = xpc_teardown_infrastructure_sn2; |
1794 | xpc_make_first_contact = xpc_make_first_contact_sn2; | 1936 | xpc_make_first_contact = xpc_make_first_contact_sn2; |
@@ -1819,9 +1961,30 @@ xpc_init_sn2(void) | |||
1819 | 1961 | ||
1820 | xpc_send_msg = xpc_send_msg_sn2; | 1962 | xpc_send_msg = xpc_send_msg_sn2; |
1821 | xpc_received_msg = xpc_received_msg_sn2; | 1963 | xpc_received_msg = xpc_received_msg_sn2; |
1964 | |||
1965 | /* open up protections for IPI and [potentially] AMO operations */ | ||
1966 | xpc_allow_IPI_ops_sn2(); | ||
1967 | xpc_allow_AMO_ops_shub_wars_1_1_sn2(); | ||
1968 | |||
1969 | /* | ||
1970 | * This is safe to do before the xpc_hb_checker thread has started | ||
1971 | * because the handler releases a wait queue. If an interrupt is | ||
1972 | * received before the thread is waiting, it will not go to sleep, | ||
1973 | * but rather immediately process the interrupt. | ||
1974 | */ | ||
1975 | ret = request_irq(SGI_XPC_ACTIVATE, xpc_handle_activate_IRQ_sn2, 0, | ||
1976 | "xpc hb", NULL); | ||
1977 | if (ret != 0) { | ||
1978 | dev_err(xpc_part, "can't register ACTIVATE IRQ handler, " | ||
1979 | "errno=%d\n", -ret); | ||
1980 | xpc_disallow_IPI_ops_sn2(); | ||
1981 | } | ||
1982 | return ret; | ||
1822 | } | 1983 | } |
1823 | 1984 | ||
1824 | void | 1985 | void |
1825 | xpc_exit_sn2(void) | 1986 | xpc_exit_sn2(void) |
1826 | { | 1987 | { |
1988 | free_irq(SGI_XPC_ACTIVATE, NULL); | ||
1989 | xpc_disallow_IPI_ops_sn2(); | ||
1827 | } | 1990 | } |