int __init xpc_init(void) { int ret; struct task_struct *kthread; dev_set_name(xpc_part, "part"); dev_set_name(xpc_chan, "chan"); if (is_shub()) { /* * The ia64-sn2 architecture supports at most 64 partitions. * And the inability to unregister remote amos restricts us * further to only support exactly 64 partitions on this * architecture, no less. */ if (xp_max_npartitions != 64) { dev_err(xpc_part, "max #of partitions not set to 64\n"); ret = -EINVAL; } else { ret = xpc_init_sn2(); } } else if (is_uv()) { ret = xpc_init_uv(); } else { ret = -ENODEV; } if (ret != 0) return ret; ret = xpc_setup_partitions(); if (ret != 0) { dev_err(xpc_part, "can't get memory for partition structure\n"); goto out_1; } xpc_sysctl = register_sysctl_table(xpc_sys_dir); /* * Fill the partition reserved page with the information needed by * other partitions to discover we are alive and establish initial * communications. */ ret = xpc_setup_rsvd_page(); if (ret != 0) { dev_err(xpc_part, "can't setup our reserved page\n"); goto out_2; } /* add ourselves to the reboot_notifier_list */ ret = register_reboot_notifier(&xpc_reboot_notifier); if (ret != 0) dev_warn(xpc_part, "can't register reboot notifier\n"); /* add ourselves to the die_notifier list */ ret = register_die_notifier(&xpc_die_notifier); if (ret != 0) dev_warn(xpc_part, "can't register die notifier\n"); /* * The real work-horse behind xpc. This processes incoming * interrupts and monitors remote heartbeats. */ kthread = kthread_run(xpc_hb_checker, NULL, XPC_HB_CHECK_THREAD_NAME); if (IS_ERR(kthread)) { dev_err(xpc_part, "failed while forking hb check thread\n"); ret = -EBUSY; goto out_3; } /* * Startup a thread that will attempt to discover other partitions to * activate based on info provided by SAL. This new thread is short * lived and will exit once discovery is complete. */ kthread = kthread_run(xpc_initiate_discovery, NULL, XPC_DISCOVERY_THREAD_NAME); if (IS_ERR(kthread)) { dev_err(xpc_part, "failed while forking discovery thread\n"); /* mark this new thread as a non-starter */ complete(&xpc_discovery_exited); xpc_do_exit(xpUnloading); return -EBUSY; } /* set the interface to point at XPC's functions */ xpc_set_interface(xpc_initiate_connect, xpc_initiate_disconnect, xpc_initiate_send, xpc_initiate_send_notify, xpc_initiate_received, xpc_initiate_partid_to_nasids); return 0; /* initialization was not successful */ out_3: xpc_teardown_rsvd_page(); (void)unregister_die_notifier(&xpc_die_notifier); (void)unregister_reboot_notifier(&xpc_reboot_notifier); out_2: if (xpc_sysctl) unregister_sysctl_table(xpc_sysctl); xpc_teardown_partitions(); out_1: if (is_shub()) xpc_exit_sn2(); else if (is_uv()) xpc_exit_uv(); return ret; }
static void xpc_do_exit(enum xp_retval reason) { short partid; int active_part_count, printed_waiting_msg = 0; struct xpc_partition *part; unsigned long printmsg_time, disengage_timeout = 0; /* */ DBUG_ON(xpc_exiting == 1); /* */ xpc_exiting = 1; wake_up_interruptible(&xpc_activate_IRQ_wq); /* */ wait_for_completion(&xpc_discovery_exited); /* */ wait_for_completion(&xpc_hb_checker_exited); /* */ (void)msleep_interruptible(300); /* */ printmsg_time = jiffies + (XPC_DEACTIVATE_PRINTMSG_INTERVAL * HZ); xpc_disengage_timedout = 0; do { active_part_count = 0; for (partid = 0; partid < xp_max_npartitions; partid++) { part = &xpc_partitions[partid]; if (xpc_partition_disengaged(part) && part->act_state == XPC_P_AS_INACTIVE) { continue; } active_part_count++; XPC_DEACTIVATE_PARTITION(part, reason); if (part->disengage_timeout > disengage_timeout) disengage_timeout = part->disengage_timeout; } if (xpc_arch_ops.any_partition_engaged()) { if (time_is_before_jiffies(printmsg_time)) { dev_info(xpc_part, "waiting for remote " "partitions to deactivate, timeout in " "%ld seconds\n", (disengage_timeout - jiffies) / HZ); printmsg_time = jiffies + (XPC_DEACTIVATE_PRINTMSG_INTERVAL * HZ); printed_waiting_msg = 1; } } else if (active_part_count > 0) { if (printed_waiting_msg) { dev_info(xpc_part, "waiting for local partition" " to deactivate\n"); printed_waiting_msg = 0; } } else { if (!xpc_disengage_timedout) { dev_info(xpc_part, "all partitions have " "deactivated\n"); } break; } /* */ (void)msleep_interruptible(300); } while (1); DBUG_ON(xpc_arch_ops.any_partition_engaged()); xpc_teardown_rsvd_page(); if (reason == xpUnloading) { (void)unregister_die_notifier(&xpc_die_notifier); (void)unregister_reboot_notifier(&xpc_reboot_notifier); } /* */ xpc_clear_interface(); if (xpc_sysctl) unregister_sysctl_table(xpc_sysctl); xpc_teardown_partitions(); if (is_shub()) xpc_exit_sn2(); else if (is_uv()) xpc_exit_uv(); }
static void xpc_do_exit(enum xp_retval reason) { short partid; int active_part_count, printed_waiting_msg = 0; struct xpc_partition *part; unsigned long printmsg_time, disengage_timeout = 0; /* a 'rmmod XPC' and a 'reboot' cannot both end up here together */ DBUG_ON(xpc_exiting == 1); /* * Let the heartbeat checker thread and the discovery thread * (if one is running) know that they should exit. Also wake up * the heartbeat checker thread in case it's sleeping. */ xpc_exiting = 1; wake_up_interruptible(&xpc_activate_IRQ_wq); /* wait for the discovery thread to exit */ wait_for_completion(&xpc_discovery_exited); /* wait for the heartbeat checker thread to exit */ wait_for_completion(&xpc_hb_checker_exited); /* sleep for a 1/3 of a second or so */ (void)msleep_interruptible(300); /* wait for all partitions to become inactive */ printmsg_time = jiffies + (XPC_DEACTIVATE_PRINTMSG_INTERVAL * HZ); xpc_disengage_timedout = 0; do { active_part_count = 0; for (partid = 0; partid < xp_max_npartitions; partid++) { part = &xpc_partitions[partid]; if (xpc_partition_disengaged(part) && part->act_state == XPC_P_AS_INACTIVE) { continue; } active_part_count++; XPC_DEACTIVATE_PARTITION(part, reason); if (part->disengage_timeout > disengage_timeout) disengage_timeout = part->disengage_timeout; } if (xpc_any_partition_engaged()) { if (time_is_before_jiffies(printmsg_time)) { dev_info(xpc_part, "waiting for remote " "partitions to deactivate, timeout in " "%ld seconds\n", (disengage_timeout - jiffies) / HZ); printmsg_time = jiffies + (XPC_DEACTIVATE_PRINTMSG_INTERVAL * HZ); printed_waiting_msg = 1; } } else if (active_part_count > 0) { if (printed_waiting_msg) { dev_info(xpc_part, "waiting for local partition" " to deactivate\n"); printed_waiting_msg = 0; } } else { if (!xpc_disengage_timedout) { dev_info(xpc_part, "all partitions have " "deactivated\n"); } break; } /* sleep for a 1/3 of a second or so */ (void)msleep_interruptible(300); } while (1); DBUG_ON(xpc_any_partition_engaged()); DBUG_ON(xpc_any_hbs_allowed() != 0); xpc_teardown_rsvd_page(); if (reason == xpUnloading) { (void)unregister_die_notifier(&xpc_die_notifier); (void)unregister_reboot_notifier(&xpc_reboot_notifier); } /* clear the interface to XPC's functions */ xpc_clear_interface(); if (xpc_sysctl) unregister_sysctl_table(xpc_sysctl); xpc_teardown_partitions(); if (is_shub()) xpc_exit_sn2(); else if (is_uv()) xpc_exit_uv(); }
int __init xpc_init(void) { int ret; struct task_struct *kthread; dev_set_name(xpc_part, "part"); dev_set_name(xpc_chan, "chan"); if (is_shub()) { /* */ if (xp_max_npartitions != 64) { dev_err(xpc_part, "max #of partitions not set to 64\n"); ret = -EINVAL; } else { ret = xpc_init_sn2(); } } else if (is_uv()) { ret = xpc_init_uv(); } else { ret = -ENODEV; } if (ret != 0) return ret; ret = xpc_setup_partitions(); if (ret != 0) { dev_err(xpc_part, "can't get memory for partition structure\n"); goto out_1; } xpc_sysctl = register_sysctl_table(xpc_sys_dir); /* */ ret = xpc_setup_rsvd_page(); if (ret != 0) { dev_err(xpc_part, "can't setup our reserved page\n"); goto out_2; } /* */ ret = register_reboot_notifier(&xpc_reboot_notifier); if (ret != 0) dev_warn(xpc_part, "can't register reboot notifier\n"); /* */ ret = register_die_notifier(&xpc_die_notifier); if (ret != 0) dev_warn(xpc_part, "can't register die notifier\n"); /* */ kthread = kthread_run(xpc_hb_checker, NULL, XPC_HB_CHECK_THREAD_NAME); if (IS_ERR(kthread)) { dev_err(xpc_part, "failed while forking hb check thread\n"); ret = -EBUSY; goto out_3; } /* */ kthread = kthread_run(xpc_initiate_discovery, NULL, XPC_DISCOVERY_THREAD_NAME); if (IS_ERR(kthread)) { dev_err(xpc_part, "failed while forking discovery thread\n"); /* */ complete(&xpc_discovery_exited); xpc_do_exit(xpUnloading); return -EBUSY; } /* */ xpc_set_interface(xpc_initiate_connect, xpc_initiate_disconnect, xpc_initiate_send, xpc_initiate_send_notify, xpc_initiate_received, xpc_initiate_partid_to_nasids); return 0; /* */ out_3: xpc_teardown_rsvd_page(); (void)unregister_die_notifier(&xpc_die_notifier); (void)unregister_reboot_notifier(&xpc_reboot_notifier); out_2: if (xpc_sysctl) unregister_sysctl_table(xpc_sysctl); xpc_teardown_partitions(); out_1: if (is_shub()) xpc_exit_sn2(); else if (is_uv()) xpc_exit_uv(); return ret; }