Exemplo n.º 1
0
/*
 * This function is called when the system is being rebooted.
 */
static int
xpc_system_reboot(struct notifier_block *nb, unsigned long event, void *unused)
{
	enum xp_retval reason;

	switch (event) {
	case SYS_RESTART:
		reason = xpSystemReboot;
		break;
	case SYS_HALT:
		reason = xpSystemHalt;
		break;
	case SYS_POWER_OFF:
		reason = xpSystemPoweroff;
		break;
	default:
		reason = xpSystemGoingDown;
	}

	xpc_do_exit(reason);
	return NOTIFY_DONE;
}
Exemplo n.º 2
0
void __exit
xpc_exit(void)
{
	xpc_do_exit(xpUnloading);
}
Exemplo n.º 3
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;
}
Exemplo n.º 4
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()) {
		/*
                                                              
                                                             
                                                          
                           
   */
		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;
}
Exemplo n.º 5
0
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;
}