diff options
Diffstat (limited to 'drivers/misc/sgi-xp/xpc_main.c')
-rw-r--r-- | drivers/misc/sgi-xp/xpc_main.c | 329 |
1 files changed, 246 insertions, 83 deletions
diff --git a/drivers/misc/sgi-xp/xpc_main.c b/drivers/misc/sgi-xp/xpc_main.c index b303c130bba8..13ec47928994 100644 --- a/drivers/misc/sgi-xp/xpc_main.c +++ b/drivers/misc/sgi-xp/xpc_main.c | |||
@@ -141,8 +141,9 @@ static struct ctl_table_header *xpc_sysctl; | |||
141 | /* non-zero if any remote partition disengage was timed out */ | 141 | /* non-zero if any remote partition disengage was timed out */ |
142 | int xpc_disengage_timedout; | 142 | int xpc_disengage_timedout; |
143 | 143 | ||
144 | /* #of activate IRQs received */ | 144 | /* #of activate IRQs received and not yet processed */ |
145 | atomic_t xpc_activate_IRQ_rcvd = ATOMIC_INIT(0); | 145 | int xpc_activate_IRQ_rcvd; |
146 | DEFINE_SPINLOCK(xpc_activate_IRQ_rcvd_lock); | ||
146 | 147 | ||
147 | /* IRQ handler notifies this wait queue on receipt of an IRQ */ | 148 | /* IRQ handler notifies this wait queue on receipt of an IRQ */ |
148 | DECLARE_WAIT_QUEUE_HEAD(xpc_activate_IRQ_wq); | 149 | DECLARE_WAIT_QUEUE_HEAD(xpc_activate_IRQ_wq); |
@@ -169,10 +170,11 @@ static struct notifier_block xpc_die_notifier = { | |||
169 | .notifier_call = xpc_system_die, | 170 | .notifier_call = xpc_system_die, |
170 | }; | 171 | }; |
171 | 172 | ||
173 | int (*xpc_setup_partitions_sn) (void); | ||
172 | enum xp_retval (*xpc_get_partition_rsvd_page_pa) (void *buf, u64 *cookie, | 174 | enum xp_retval (*xpc_get_partition_rsvd_page_pa) (void *buf, u64 *cookie, |
173 | unsigned long *rp_pa, | 175 | unsigned long *rp_pa, |
174 | size_t *len); | 176 | size_t *len); |
175 | enum xp_retval (*xpc_rsvd_page_init) (struct xpc_rsvd_page *rp); | 177 | int (*xpc_setup_rsvd_page_sn) (struct xpc_rsvd_page *rp); |
176 | void (*xpc_heartbeat_init) (void); | 178 | void (*xpc_heartbeat_init) (void); |
177 | void (*xpc_heartbeat_exit) (void); | 179 | void (*xpc_heartbeat_exit) (void); |
178 | void (*xpc_increment_heartbeat) (void); | 180 | void (*xpc_increment_heartbeat) (void); |
@@ -183,8 +185,8 @@ enum xp_retval (*xpc_get_remote_heartbeat) (struct xpc_partition *part); | |||
183 | enum xp_retval (*xpc_make_first_contact) (struct xpc_partition *part); | 185 | enum xp_retval (*xpc_make_first_contact) (struct xpc_partition *part); |
184 | void (*xpc_notify_senders_of_disconnect) (struct xpc_channel *ch); | 186 | void (*xpc_notify_senders_of_disconnect) (struct xpc_channel *ch); |
185 | u64 (*xpc_get_chctl_all_flags) (struct xpc_partition *part); | 187 | u64 (*xpc_get_chctl_all_flags) (struct xpc_partition *part); |
186 | enum xp_retval (*xpc_allocate_msgqueues) (struct xpc_channel *ch); | 188 | enum xp_retval (*xpc_setup_msg_structures) (struct xpc_channel *ch); |
187 | void (*xpc_free_msgqueues) (struct xpc_channel *ch); | 189 | void (*xpc_teardown_msg_structures) (struct xpc_channel *ch); |
188 | void (*xpc_process_msg_chctl_flags) (struct xpc_partition *part, int ch_number); | 190 | void (*xpc_process_msg_chctl_flags) (struct xpc_partition *part, int ch_number); |
189 | int (*xpc_n_of_deliverable_msgs) (struct xpc_channel *ch); | 191 | int (*xpc_n_of_deliverable_msgs) (struct xpc_channel *ch); |
190 | struct xpc_msg *(*xpc_get_deliverable_msg) (struct xpc_channel *ch); | 192 | struct xpc_msg *(*xpc_get_deliverable_msg) (struct xpc_channel *ch); |
@@ -196,9 +198,9 @@ void (*xpc_request_partition_reactivation) (struct xpc_partition *part); | |||
196 | void (*xpc_request_partition_deactivation) (struct xpc_partition *part); | 198 | void (*xpc_request_partition_deactivation) (struct xpc_partition *part); |
197 | void (*xpc_cancel_partition_deactivation_request) (struct xpc_partition *part); | 199 | void (*xpc_cancel_partition_deactivation_request) (struct xpc_partition *part); |
198 | 200 | ||
199 | void (*xpc_process_activate_IRQ_rcvd) (int n_IRQs_expected); | 201 | void (*xpc_process_activate_IRQ_rcvd) (void); |
200 | enum xp_retval (*xpc_setup_infrastructure) (struct xpc_partition *part); | 202 | enum xp_retval (*xpc_setup_ch_structures_sn) (struct xpc_partition *part); |
201 | void (*xpc_teardown_infrastructure) (struct xpc_partition *part); | 203 | void (*xpc_teardown_ch_structures_sn) (struct xpc_partition *part); |
202 | 204 | ||
203 | void (*xpc_indicate_partition_engaged) (struct xpc_partition *part); | 205 | void (*xpc_indicate_partition_engaged) (struct xpc_partition *part); |
204 | int (*xpc_partition_engaged) (short partid); | 206 | int (*xpc_partition_engaged) (short partid); |
@@ -215,6 +217,9 @@ void (*xpc_send_chctl_openrequest) (struct xpc_channel *ch, | |||
215 | void (*xpc_send_chctl_openreply) (struct xpc_channel *ch, | 217 | void (*xpc_send_chctl_openreply) (struct xpc_channel *ch, |
216 | unsigned long *irq_flags); | 218 | unsigned long *irq_flags); |
217 | 219 | ||
220 | void (*xpc_save_remote_msgqueue_pa) (struct xpc_channel *ch, | ||
221 | unsigned long msgqueue_pa); | ||
222 | |||
218 | enum xp_retval (*xpc_send_msg) (struct xpc_channel *ch, u32 flags, | 223 | enum xp_retval (*xpc_send_msg) (struct xpc_channel *ch, u32 flags, |
219 | void *payload, u16 payload_size, u8 notify_type, | 224 | void *payload, u16 payload_size, u8 notify_type, |
220 | xpc_notify_func func, void *key); | 225 | xpc_notify_func func, void *key); |
@@ -308,8 +313,6 @@ xpc_check_remote_hb(void) | |||
308 | static int | 313 | static int |
309 | xpc_hb_checker(void *ignore) | 314 | xpc_hb_checker(void *ignore) |
310 | { | 315 | { |
311 | int last_IRQ_count = 0; | ||
312 | int new_IRQ_count; | ||
313 | int force_IRQ = 0; | 316 | int force_IRQ = 0; |
314 | 317 | ||
315 | /* this thread was marked active by xpc_hb_init() */ | 318 | /* this thread was marked active by xpc_hb_init() */ |
@@ -325,43 +328,37 @@ xpc_hb_checker(void *ignore) | |||
325 | dev_dbg(xpc_part, "woke up with %d ticks rem; %d IRQs have " | 328 | dev_dbg(xpc_part, "woke up with %d ticks rem; %d IRQs have " |
326 | "been received\n", | 329 | "been received\n", |
327 | (int)(xpc_hb_check_timeout - jiffies), | 330 | (int)(xpc_hb_check_timeout - jiffies), |
328 | atomic_read(&xpc_activate_IRQ_rcvd) - last_IRQ_count); | 331 | xpc_activate_IRQ_rcvd); |
329 | 332 | ||
330 | /* checking of remote heartbeats is skewed by IRQ handling */ | 333 | /* checking of remote heartbeats is skewed by IRQ handling */ |
331 | if (time_is_before_eq_jiffies(xpc_hb_check_timeout)) { | 334 | if (time_is_before_eq_jiffies(xpc_hb_check_timeout)) { |
335 | xpc_hb_check_timeout = jiffies + | ||
336 | (xpc_hb_check_interval * HZ); | ||
337 | |||
332 | dev_dbg(xpc_part, "checking remote heartbeats\n"); | 338 | dev_dbg(xpc_part, "checking remote heartbeats\n"); |
333 | xpc_check_remote_hb(); | 339 | xpc_check_remote_hb(); |
334 | 340 | ||
335 | /* | 341 | /* |
336 | * We need to periodically recheck to ensure no | 342 | * On sn2 we need to periodically recheck to ensure no |
337 | * IRQ/amo pairs have been missed. That check | 343 | * IRQ/amo pairs have been missed. |
338 | * must always reset xpc_hb_check_timeout. | ||
339 | */ | 344 | */ |
340 | force_IRQ = 1; | 345 | if (is_shub()) |
346 | force_IRQ = 1; | ||
341 | } | 347 | } |
342 | 348 | ||
343 | /* check for outstanding IRQs */ | 349 | /* check for outstanding IRQs */ |
344 | new_IRQ_count = atomic_read(&xpc_activate_IRQ_rcvd); | 350 | if (xpc_activate_IRQ_rcvd > 0 || force_IRQ != 0) { |
345 | if (last_IRQ_count < new_IRQ_count || force_IRQ != 0) { | ||
346 | force_IRQ = 0; | 351 | force_IRQ = 0; |
347 | 352 | dev_dbg(xpc_part, "processing activate IRQs " | |
348 | dev_dbg(xpc_part, "found an IRQ to process; will be " | 353 | "received\n"); |
349 | "resetting xpc_hb_check_timeout\n"); | 354 | xpc_process_activate_IRQ_rcvd(); |
350 | |||
351 | xpc_process_activate_IRQ_rcvd(new_IRQ_count - | ||
352 | last_IRQ_count); | ||
353 | last_IRQ_count = new_IRQ_count; | ||
354 | |||
355 | xpc_hb_check_timeout = jiffies + | ||
356 | (xpc_hb_check_interval * HZ); | ||
357 | } | 355 | } |
358 | 356 | ||
359 | /* wait for IRQ or timeout */ | 357 | /* wait for IRQ or timeout */ |
360 | (void)wait_event_interruptible(xpc_activate_IRQ_wq, | 358 | (void)wait_event_interruptible(xpc_activate_IRQ_wq, |
361 | (last_IRQ_count < atomic_read( | 359 | (time_is_before_eq_jiffies( |
362 | &xpc_activate_IRQ_rcvd) | ||
363 | || time_is_before_eq_jiffies( | ||
364 | xpc_hb_check_timeout) || | 360 | xpc_hb_check_timeout) || |
361 | xpc_activate_IRQ_rcvd > 0 || | ||
365 | xpc_exiting)); | 362 | xpc_exiting)); |
366 | } | 363 | } |
367 | 364 | ||
@@ -437,6 +434,153 @@ xpc_channel_mgr(struct xpc_partition *part) | |||
437 | } | 434 | } |
438 | 435 | ||
439 | /* | 436 | /* |
437 | * Guarantee that the kzalloc'd memory is cacheline aligned. | ||
438 | */ | ||
439 | void * | ||
440 | xpc_kzalloc_cacheline_aligned(size_t size, gfp_t flags, void **base) | ||
441 | { | ||
442 | /* see if kzalloc will give us cachline aligned memory by default */ | ||
443 | *base = kzalloc(size, flags); | ||
444 | if (*base == NULL) | ||
445 | return NULL; | ||
446 | |||
447 | if ((u64)*base == L1_CACHE_ALIGN((u64)*base)) | ||
448 | return *base; | ||
449 | |||
450 | kfree(*base); | ||
451 | |||
452 | /* nope, we'll have to do it ourselves */ | ||
453 | *base = kzalloc(size + L1_CACHE_BYTES, flags); | ||
454 | if (*base == NULL) | ||
455 | return NULL; | ||
456 | |||
457 | return (void *)L1_CACHE_ALIGN((u64)*base); | ||
458 | } | ||
459 | |||
460 | /* | ||
461 | * Setup the channel structures necessary to support XPartition Communication | ||
462 | * between the specified remote partition and the local one. | ||
463 | */ | ||
464 | static enum xp_retval | ||
465 | xpc_setup_ch_structures(struct xpc_partition *part) | ||
466 | { | ||
467 | enum xp_retval ret; | ||
468 | int ch_number; | ||
469 | struct xpc_channel *ch; | ||
470 | short partid = XPC_PARTID(part); | ||
471 | |||
472 | /* | ||
473 | * Allocate all of the channel structures as a contiguous chunk of | ||
474 | * memory. | ||
475 | */ | ||
476 | DBUG_ON(part->channels != NULL); | ||
477 | part->channels = kzalloc(sizeof(struct xpc_channel) * XPC_MAX_NCHANNELS, | ||
478 | GFP_KERNEL); | ||
479 | if (part->channels == NULL) { | ||
480 | dev_err(xpc_chan, "can't get memory for channels\n"); | ||
481 | return xpNoMemory; | ||
482 | } | ||
483 | |||
484 | /* allocate the remote open and close args */ | ||
485 | |||
486 | part->remote_openclose_args = | ||
487 | xpc_kzalloc_cacheline_aligned(XPC_OPENCLOSE_ARGS_SIZE, | ||
488 | GFP_KERNEL, &part-> | ||
489 | remote_openclose_args_base); | ||
490 | if (part->remote_openclose_args == NULL) { | ||
491 | dev_err(xpc_chan, "can't get memory for remote connect args\n"); | ||
492 | ret = xpNoMemory; | ||
493 | goto out_1; | ||
494 | } | ||
495 | |||
496 | part->chctl.all_flags = 0; | ||
497 | spin_lock_init(&part->chctl_lock); | ||
498 | |||
499 | atomic_set(&part->channel_mgr_requests, 1); | ||
500 | init_waitqueue_head(&part->channel_mgr_wq); | ||
501 | |||
502 | part->nchannels = XPC_MAX_NCHANNELS; | ||
503 | |||
504 | atomic_set(&part->nchannels_active, 0); | ||
505 | atomic_set(&part->nchannels_engaged, 0); | ||
506 | |||
507 | for (ch_number = 0; ch_number < part->nchannels; ch_number++) { | ||
508 | ch = &part->channels[ch_number]; | ||
509 | |||
510 | ch->partid = partid; | ||
511 | ch->number = ch_number; | ||
512 | ch->flags = XPC_C_DISCONNECTED; | ||
513 | |||
514 | atomic_set(&ch->kthreads_assigned, 0); | ||
515 | atomic_set(&ch->kthreads_idle, 0); | ||
516 | atomic_set(&ch->kthreads_active, 0); | ||
517 | |||
518 | atomic_set(&ch->references, 0); | ||
519 | atomic_set(&ch->n_to_notify, 0); | ||
520 | |||
521 | spin_lock_init(&ch->lock); | ||
522 | init_completion(&ch->wdisconnect_wait); | ||
523 | |||
524 | atomic_set(&ch->n_on_msg_allocate_wq, 0); | ||
525 | init_waitqueue_head(&ch->msg_allocate_wq); | ||
526 | init_waitqueue_head(&ch->idle_wq); | ||
527 | } | ||
528 | |||
529 | ret = xpc_setup_ch_structures_sn(part); | ||
530 | if (ret != xpSuccess) | ||
531 | goto out_2; | ||
532 | |||
533 | /* | ||
534 | * With the setting of the partition setup_state to XPC_P_SS_SETUP, | ||
535 | * we're declaring that this partition is ready to go. | ||
536 | */ | ||
537 | part->setup_state = XPC_P_SS_SETUP; | ||
538 | |||
539 | return xpSuccess; | ||
540 | |||
541 | /* setup of ch structures failed */ | ||
542 | out_2: | ||
543 | kfree(part->remote_openclose_args_base); | ||
544 | part->remote_openclose_args = NULL; | ||
545 | out_1: | ||
546 | kfree(part->channels); | ||
547 | part->channels = NULL; | ||
548 | return ret; | ||
549 | } | ||
550 | |||
551 | /* | ||
552 | * Teardown the channel structures necessary to support XPartition Communication | ||
553 | * between the specified remote partition and the local one. | ||
554 | */ | ||
555 | static void | ||
556 | xpc_teardown_ch_structures(struct xpc_partition *part) | ||
557 | { | ||
558 | DBUG_ON(atomic_read(&part->nchannels_engaged) != 0); | ||
559 | DBUG_ON(atomic_read(&part->nchannels_active) != 0); | ||
560 | |||
561 | /* | ||
562 | * Make this partition inaccessible to local processes by marking it | ||
563 | * as no longer setup. Then wait before proceeding with the teardown | ||
564 | * until all existing references cease. | ||
565 | */ | ||
566 | DBUG_ON(part->setup_state != XPC_P_SS_SETUP); | ||
567 | part->setup_state = XPC_P_SS_WTEARDOWN; | ||
568 | |||
569 | wait_event(part->teardown_wq, (atomic_read(&part->references) == 0)); | ||
570 | |||
571 | /* now we can begin tearing down the infrastructure */ | ||
572 | |||
573 | xpc_teardown_ch_structures_sn(part); | ||
574 | |||
575 | kfree(part->remote_openclose_args_base); | ||
576 | part->remote_openclose_args = NULL; | ||
577 | kfree(part->channels); | ||
578 | part->channels = NULL; | ||
579 | |||
580 | part->setup_state = XPC_P_SS_TORNDOWN; | ||
581 | } | ||
582 | |||
583 | /* | ||
440 | * When XPC HB determines that a partition has come up, it will create a new | 584 | * When XPC HB determines that a partition has come up, it will create a new |
441 | * kthread and that kthread will call this function to attempt to set up the | 585 | * kthread and that kthread will call this function to attempt to set up the |
442 | * basic infrastructure used for Cross Partition Communication with the newly | 586 | * basic infrastructure used for Cross Partition Communication with the newly |
@@ -476,7 +620,7 @@ xpc_activating(void *__partid) | |||
476 | 620 | ||
477 | xpc_allow_hb(partid); | 621 | xpc_allow_hb(partid); |
478 | 622 | ||
479 | if (xpc_setup_infrastructure(part) == xpSuccess) { | 623 | if (xpc_setup_ch_structures(part) == xpSuccess) { |
480 | (void)xpc_part_ref(part); /* this will always succeed */ | 624 | (void)xpc_part_ref(part); /* this will always succeed */ |
481 | 625 | ||
482 | if (xpc_make_first_contact(part) == xpSuccess) { | 626 | if (xpc_make_first_contact(part) == xpSuccess) { |
@@ -486,7 +630,7 @@ xpc_activating(void *__partid) | |||
486 | } | 630 | } |
487 | 631 | ||
488 | xpc_part_deref(part); | 632 | xpc_part_deref(part); |
489 | xpc_teardown_infrastructure(part); | 633 | xpc_teardown_ch_structures(part); |
490 | } | 634 | } |
491 | 635 | ||
492 | xpc_disallow_hb(partid); | 636 | xpc_disallow_hb(partid); |
@@ -806,6 +950,56 @@ xpc_disconnect_wait(int ch_number) | |||
806 | } | 950 | } |
807 | } | 951 | } |
808 | 952 | ||
953 | static int | ||
954 | xpc_setup_partitions(void) | ||
955 | { | ||
956 | short partid; | ||
957 | struct xpc_partition *part; | ||
958 | |||
959 | xpc_partitions = kzalloc(sizeof(struct xpc_partition) * | ||
960 | xp_max_npartitions, GFP_KERNEL); | ||
961 | if (xpc_partitions == NULL) { | ||
962 | dev_err(xpc_part, "can't get memory for partition structure\n"); | ||
963 | return -ENOMEM; | ||
964 | } | ||
965 | |||
966 | /* | ||
967 | * The first few fields of each entry of xpc_partitions[] need to | ||
968 | * be initialized now so that calls to xpc_connect() and | ||
969 | * xpc_disconnect() can be made prior to the activation of any remote | ||
970 | * partition. NOTE THAT NONE OF THE OTHER FIELDS BELONGING TO THESE | ||
971 | * ENTRIES ARE MEANINGFUL UNTIL AFTER AN ENTRY'S CORRESPONDING | ||
972 | * PARTITION HAS BEEN ACTIVATED. | ||
973 | */ | ||
974 | for (partid = 0; partid < xp_max_npartitions; partid++) { | ||
975 | part = &xpc_partitions[partid]; | ||
976 | |||
977 | DBUG_ON((u64)part != L1_CACHE_ALIGN((u64)part)); | ||
978 | |||
979 | part->activate_IRQ_rcvd = 0; | ||
980 | spin_lock_init(&part->act_lock); | ||
981 | part->act_state = XPC_P_AS_INACTIVE; | ||
982 | XPC_SET_REASON(part, 0, 0); | ||
983 | |||
984 | init_timer(&part->disengage_timer); | ||
985 | part->disengage_timer.function = | ||
986 | xpc_timeout_partition_disengage; | ||
987 | part->disengage_timer.data = (unsigned long)part; | ||
988 | |||
989 | part->setup_state = XPC_P_SS_UNSET; | ||
990 | init_waitqueue_head(&part->teardown_wq); | ||
991 | atomic_set(&part->references, 0); | ||
992 | } | ||
993 | |||
994 | return xpc_setup_partitions_sn(); | ||
995 | } | ||
996 | |||
997 | static void | ||
998 | xpc_teardown_partitions(void) | ||
999 | { | ||
1000 | kfree(xpc_partitions); | ||
1001 | } | ||
1002 | |||
809 | static void | 1003 | static void |
810 | xpc_do_exit(enum xp_retval reason) | 1004 | xpc_do_exit(enum xp_retval reason) |
811 | { | 1005 | { |
@@ -892,8 +1086,7 @@ xpc_do_exit(enum xp_retval reason) | |||
892 | DBUG_ON(xpc_any_partition_engaged()); | 1086 | DBUG_ON(xpc_any_partition_engaged()); |
893 | DBUG_ON(xpc_any_hbs_allowed() != 0); | 1087 | DBUG_ON(xpc_any_hbs_allowed() != 0); |
894 | 1088 | ||
895 | /* a zero timestamp indicates our rsvd page is not initialized */ | 1089 | xpc_teardown_rsvd_page(); |
896 | xpc_rsvd_page->ts_jiffies = 0; | ||
897 | 1090 | ||
898 | if (reason == xpUnloading) { | 1091 | if (reason == xpUnloading) { |
899 | (void)unregister_die_notifier(&xpc_die_notifier); | 1092 | (void)unregister_die_notifier(&xpc_die_notifier); |
@@ -906,7 +1099,7 @@ xpc_do_exit(enum xp_retval reason) | |||
906 | if (xpc_sysctl) | 1099 | if (xpc_sysctl) |
907 | unregister_sysctl_table(xpc_sysctl); | 1100 | unregister_sysctl_table(xpc_sysctl); |
908 | 1101 | ||
909 | kfree(xpc_partitions); | 1102 | xpc_teardown_partitions(); |
910 | 1103 | ||
911 | if (is_shub()) | 1104 | if (is_shub()) |
912 | xpc_exit_sn2(); | 1105 | xpc_exit_sn2(); |
@@ -1062,8 +1255,6 @@ int __init | |||
1062 | xpc_init(void) | 1255 | xpc_init(void) |
1063 | { | 1256 | { |
1064 | int ret; | 1257 | int ret; |
1065 | short partid; | ||
1066 | struct xpc_partition *part; | ||
1067 | struct task_struct *kthread; | 1258 | struct task_struct *kthread; |
1068 | 1259 | ||
1069 | snprintf(xpc_part->bus_id, BUS_ID_SIZE, "part"); | 1260 | snprintf(xpc_part->bus_id, BUS_ID_SIZE, "part"); |
@@ -1076,56 +1267,29 @@ xpc_init(void) | |||
1076 | * further to only support exactly 64 partitions on this | 1267 | * further to only support exactly 64 partitions on this |
1077 | * architecture, no less. | 1268 | * architecture, no less. |
1078 | */ | 1269 | */ |
1079 | if (xp_max_npartitions != 64) | 1270 | if (xp_max_npartitions != 64) { |
1080 | return -EINVAL; | 1271 | dev_err(xpc_part, "max #of partitions not set to 64\n"); |
1081 | 1272 | ret = -EINVAL; | |
1082 | ret = xpc_init_sn2(); | 1273 | } else { |
1083 | if (ret != 0) | 1274 | ret = xpc_init_sn2(); |
1084 | return ret; | 1275 | } |
1085 | 1276 | ||
1086 | } else if (is_uv()) { | 1277 | } else if (is_uv()) { |
1087 | xpc_init_uv(); | 1278 | ret = xpc_init_uv(); |
1088 | 1279 | ||
1089 | } else { | 1280 | } else { |
1090 | return -ENODEV; | 1281 | ret = -ENODEV; |
1091 | } | 1282 | } |
1092 | 1283 | ||
1093 | xpc_partitions = kzalloc(sizeof(struct xpc_partition) * | 1284 | if (ret != 0) |
1094 | xp_max_npartitions, GFP_KERNEL); | 1285 | return ret; |
1095 | if (xpc_partitions == NULL) { | 1286 | |
1287 | ret = xpc_setup_partitions(); | ||
1288 | if (ret != 0) { | ||
1096 | dev_err(xpc_part, "can't get memory for partition structure\n"); | 1289 | dev_err(xpc_part, "can't get memory for partition structure\n"); |
1097 | ret = -ENOMEM; | ||
1098 | goto out_1; | 1290 | goto out_1; |
1099 | } | 1291 | } |
1100 | 1292 | ||
1101 | /* | ||
1102 | * The first few fields of each entry of xpc_partitions[] need to | ||
1103 | * be initialized now so that calls to xpc_connect() and | ||
1104 | * xpc_disconnect() can be made prior to the activation of any remote | ||
1105 | * partition. NOTE THAT NONE OF THE OTHER FIELDS BELONGING TO THESE | ||
1106 | * ENTRIES ARE MEANINGFUL UNTIL AFTER AN ENTRY'S CORRESPONDING | ||
1107 | * PARTITION HAS BEEN ACTIVATED. | ||
1108 | */ | ||
1109 | for (partid = 0; partid < xp_max_npartitions; partid++) { | ||
1110 | part = &xpc_partitions[partid]; | ||
1111 | |||
1112 | DBUG_ON((u64)part != L1_CACHE_ALIGN((u64)part)); | ||
1113 | |||
1114 | part->activate_IRQ_rcvd = 0; | ||
1115 | spin_lock_init(&part->act_lock); | ||
1116 | part->act_state = XPC_P_AS_INACTIVE; | ||
1117 | XPC_SET_REASON(part, 0, 0); | ||
1118 | |||
1119 | init_timer(&part->disengage_timer); | ||
1120 | part->disengage_timer.function = | ||
1121 | xpc_timeout_partition_disengage; | ||
1122 | part->disengage_timer.data = (unsigned long)part; | ||
1123 | |||
1124 | part->setup_state = XPC_P_SS_UNSET; | ||
1125 | init_waitqueue_head(&part->teardown_wq); | ||
1126 | atomic_set(&part->references, 0); | ||
1127 | } | ||
1128 | |||
1129 | xpc_sysctl = register_sysctl_table(xpc_sys_dir); | 1293 | xpc_sysctl = register_sysctl_table(xpc_sys_dir); |
1130 | 1294 | ||
1131 | /* | 1295 | /* |
@@ -1133,10 +1297,9 @@ xpc_init(void) | |||
1133 | * other partitions to discover we are alive and establish initial | 1297 | * other partitions to discover we are alive and establish initial |
1134 | * communications. | 1298 | * communications. |
1135 | */ | 1299 | */ |
1136 | xpc_rsvd_page = xpc_setup_rsvd_page(); | 1300 | ret = xpc_setup_rsvd_page(); |
1137 | if (xpc_rsvd_page == NULL) { | 1301 | if (ret != 0) { |
1138 | dev_err(xpc_part, "can't setup our reserved page\n"); | 1302 | dev_err(xpc_part, "can't setup our reserved page\n"); |
1139 | ret = -EBUSY; | ||
1140 | goto out_2; | 1303 | goto out_2; |
1141 | } | 1304 | } |
1142 | 1305 | ||
@@ -1187,15 +1350,15 @@ xpc_init(void) | |||
1187 | 1350 | ||
1188 | /* initialization was not successful */ | 1351 | /* initialization was not successful */ |
1189 | out_3: | 1352 | out_3: |
1190 | /* a zero timestamp indicates our rsvd page is not initialized */ | 1353 | xpc_teardown_rsvd_page(); |
1191 | xpc_rsvd_page->ts_jiffies = 0; | ||
1192 | 1354 | ||
1193 | (void)unregister_die_notifier(&xpc_die_notifier); | 1355 | (void)unregister_die_notifier(&xpc_die_notifier); |
1194 | (void)unregister_reboot_notifier(&xpc_reboot_notifier); | 1356 | (void)unregister_reboot_notifier(&xpc_reboot_notifier); |
1195 | out_2: | 1357 | out_2: |
1196 | if (xpc_sysctl) | 1358 | if (xpc_sysctl) |
1197 | unregister_sysctl_table(xpc_sysctl); | 1359 | unregister_sysctl_table(xpc_sysctl); |
1198 | kfree(xpc_partitions); | 1360 | |
1361 | xpc_teardown_partitions(); | ||
1199 | out_1: | 1362 | out_1: |
1200 | if (is_shub()) | 1363 | if (is_shub()) |
1201 | xpc_exit_sn2(); | 1364 | xpc_exit_sn2(); |