void __exit xp_exit(void) { if (is_shub()) xp_exit_sn2(); else if (is_uv()) xp_exit_uv(); }
enum xp_retval xp_init_uv(void) { BUG_ON(!is_uv()); xp_max_npartitions = XP_MAX_NPARTITIONS_UV; xp_partition_id = sn_partition_id; xp_region_size = sn_region_size; xp_pa = xp_pa_uv; xp_socket_pa = xp_socket_pa_uv; xp_remote_memcpy = xp_remote_memcpy_uv; xp_cpu_to_nasid = xp_cpu_to_nasid_uv; xp_expand_memprotect = xp_expand_memprotect_uv; xp_restrict_memprotect = xp_restrict_memprotect_uv; return xpSuccess; }
int __init xp_init(void) { enum xp_retval ret; int ch_number; for (ch_number = 0; ch_number < XPC_MAX_NCHANNELS; ch_number++) mutex_init(&xpc_registrations[ch_number].mutex); if (is_shub()) ret = xp_init_sn2(); else if (is_uv()) ret = xp_init_uv(); else ret = 0; if (ret != xpSuccess) return ret; return 0; }
int __init xp_init(void) { enum xp_retval ret; int ch_number; if (is_shub()) ret = xp_init_sn2(); else if (is_uv()) ret = xp_init_uv(); else ret = xpUnsupported; if (ret != xpSuccess) return -ENODEV; /* initialize the connection registration mutex */ for (ch_number = 0; ch_number < XPC_MAX_NCHANNELS; ch_number++) mutex_init(&xpc_registrations[ch_number].mutex); return 0; }
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; /* 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(); }
void xp_exit_uv(void) { BUG_ON(!is_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; /* */ 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(); }
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; }
/* * SAL has provided a partition and machine mask. The partition mask * contains a bit for each even nasid in our partition. The machine * mask contains a bit for each even nasid in the entire machine. * * Using those two bit arrays, we can determine which nasids are * known in the machine. Each should also have a reserved page * initialized if they are available for partitioning. */ void xpc_discovery(void) { void *remote_rp_base; struct xpc_rsvd_page *remote_rp; unsigned long remote_rp_pa; int region; int region_size; int max_regions; int nasid; struct xpc_rsvd_page *rp; unsigned long *discovered_nasids; enum xp_retval ret; remote_rp = xpc_kmalloc_cacheline_aligned(XPC_RP_HEADER_SIZE + xpc_nasid_mask_nbytes, GFP_KERNEL, &remote_rp_base); if (remote_rp == NULL) return; discovered_nasids = kzalloc(sizeof(long) * xpc_nasid_mask_nlongs, GFP_KERNEL); if (discovered_nasids == NULL) { kfree(remote_rp_base); return; } rp = (struct xpc_rsvd_page *)xpc_rsvd_page; /* * The term 'region' in this context refers to the minimum number of * nodes that can comprise an access protection grouping. The access * protection is in regards to memory, IOI and IPI. */ region_size = xp_region_size; if (is_uv()) max_regions = 256; else { max_regions = 64; switch (region_size) { case 128: max_regions *= 2; case 64: max_regions *= 2; case 32: max_regions *= 2; region_size = 16; DBUG_ON(!is_shub2()); } } for (region = 0; region < max_regions; region++) { if (xpc_exiting) break; dev_dbg(xpc_part, "searching region %d\n", region); for (nasid = (region * region_size * 2); nasid < ((region + 1) * region_size * 2); nasid += 2) { if (xpc_exiting) break; dev_dbg(xpc_part, "checking nasid %d\n", nasid); if (test_bit(nasid / 2, xpc_part_nasids)) { dev_dbg(xpc_part, "PROM indicates Nasid %d is " "part of the local partition; skipping " "region\n", nasid); break; } if (!(test_bit(nasid / 2, xpc_mach_nasids))) { dev_dbg(xpc_part, "PROM indicates Nasid %d was " "not on Numa-Link network at reset\n", nasid); continue; } if (test_bit(nasid / 2, discovered_nasids)) { dev_dbg(xpc_part, "Nasid %d is part of a " "partition which was previously " "discovered\n", nasid); continue; } /* pull over the rsvd page header & part_nasids mask */ ret = xpc_get_remote_rp(nasid, discovered_nasids, remote_rp, &remote_rp_pa); if (ret != xpSuccess) { dev_dbg(xpc_part, "unable to get reserved page " "from nasid %d, reason=%d\n", nasid, ret); if (ret == xpLocalPartid) break; continue; } xpc_arch_ops.request_partition_activation(remote_rp, remote_rp_pa, nasid); } } kfree(discovered_nasids); kfree(remote_rp_base); }