예제 #1
0
void __exit
xp_exit(void)
{
	if (is_shub())
		xp_exit_sn2();
	else if (is_uv())
		xp_exit_uv();
}
예제 #2
0
파일: xp_uv.c 프로젝트: 020gzh/linux
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;
}
예제 #3
0
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;
}
예제 #4
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;
}
예제 #5
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;
}
예제 #6
0
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();
}
예제 #7
0
파일: xp_uv.c 프로젝트: 020gzh/linux
void
xp_exit_uv(void)
{
	BUG_ON(!is_uv());
}
예제 #8
0
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();
}
예제 #9
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;
}
예제 #10
0
/*
 * 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);
}