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; }
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; }
int __init xpc_init(void) { int ret; short partid; struct xpc_partition *part; struct task_struct *kthread; size_t buf_size; if (!ia64_platform_is("sn2")) return -ENODEV; buf_size = max(XPC_RP_VARS_SIZE, XPC_RP_HEADER_SIZE + XP_NASID_MASK_BYTES); xpc_remote_copy_buffer = xpc_kmalloc_cacheline_aligned(buf_size, GFP_KERNEL, &xpc_remote_copy_buffer_base); if (xpc_remote_copy_buffer == NULL) return -ENOMEM; snprintf(xpc_part->bus_id, BUS_ID_SIZE, "part"); snprintf(xpc_chan->bus_id, BUS_ID_SIZE, "chan"); xpc_sysctl = register_sysctl_table(xpc_sys_dir); /* * The first few fields of each entry of xpc_partitions[] need to * be initialized now so that calls to xpc_connect() and * xpc_disconnect() can be made prior to the activation of any remote * partition. NOTE THAT NONE OF THE OTHER FIELDS BELONGING TO THESE * ENTRIES ARE MEANINGFUL UNTIL AFTER AN ENTRY'S CORRESPONDING * PARTITION HAS BEEN ACTIVATED. */ for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) { part = &xpc_partitions[partid]; DBUG_ON((u64)part != L1_CACHE_ALIGN((u64)part)); part->act_IRQ_rcvd = 0; spin_lock_init(&part->act_lock); part->act_state = XPC_P_INACTIVE; XPC_SET_REASON(part, 0, 0); init_timer(&part->disengage_request_timer); part->disengage_request_timer.function = xpc_timeout_partition_disengage_request; part->disengage_request_timer.data = (unsigned long)part; part->setup_state = XPC_P_UNSET; init_waitqueue_head(&part->teardown_wq); atomic_set(&part->references, 0); } /* * Open up protections for IPI operations (and AMO operations on * Shub 1.1 systems). */ xpc_allow_IPI_ops(); /* * Interrupts being processed will increment this atomic variable and * awaken the heartbeat thread which will process the interrupts. */ atomic_set(&xpc_act_IRQ_rcvd, 0); /* * This is safe to do before the xpc_hb_checker thread has started * because the handler releases a wait queue. If an interrupt is * received before the thread is waiting, it will not go to sleep, * but rather immediately process the interrupt. */ ret = request_irq(SGI_XPC_ACTIVATE, xpc_act_IRQ_handler, 0, "xpc hb", NULL); if (ret != 0) { dev_err(xpc_part, "can't register ACTIVATE IRQ handler, " "errno=%d\n", -ret); xpc_restrict_IPI_ops(); if (xpc_sysctl) unregister_sysctl_table(xpc_sysctl); kfree(xpc_remote_copy_buffer_base); return -EBUSY; } /* * Fill the partition reserved page with the information needed by * other partitions to discover we are alive and establish initial * communications. */ xpc_rsvd_page = xpc_rsvd_page_init(); if (xpc_rsvd_page == NULL) { dev_err(xpc_part, "could not setup our reserved page\n"); free_irq(SGI_XPC_ACTIVATE, NULL); xpc_restrict_IPI_ops(); if (xpc_sysctl) unregister_sysctl_table(xpc_sysctl); kfree(xpc_remote_copy_buffer_base); return -EBUSY; } /* 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"); init_timer(&xpc_hb_timer); xpc_hb_timer.function = xpc_hb_beater; /* * 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"); /* indicate to others that our reserved page is uninitialized */ xpc_rsvd_page->vars_pa = 0; /* take ourselves off of the reboot_notifier_list */ (void)unregister_reboot_notifier(&xpc_reboot_notifier); /* take ourselves off of the die_notifier list */ (void)unregister_die_notifier(&xpc_die_notifier); del_timer_sync(&xpc_hb_timer); free_irq(SGI_XPC_ACTIVATE, NULL); xpc_restrict_IPI_ops(); if (xpc_sysctl) unregister_sysctl_table(xpc_sysctl); kfree(xpc_remote_copy_buffer_base); return -EBUSY; } /* * 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_allocate, xpc_initiate_send, xpc_initiate_send_notify, xpc_initiate_received, xpc_initiate_partid_to_nasids); return 0; }