sgi-xp: support runtime selection of xp_max_npartitions

Support runtime selection of the max number of partitions based on the
hardware being run on.

Signed-off-by: Dean Nelson <dcn@sgi.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
diff --git a/drivers/misc/sgi-xp/xpc_main.c b/drivers/misc/sgi-xp/xpc_main.c
index c3b4227..a05c7c7 100644
--- a/drivers/misc/sgi-xp/xpc_main.c
+++ b/drivers/misc/sgi-xp/xpc_main.c
@@ -433,7 +433,7 @@
 	struct xpc_partition *part = &xpc_partitions[partid];
 	unsigned long irq_flags;
 
-	DBUG_ON(partid <= 0 || partid >= XP_MAX_PARTITIONS);
+	DBUG_ON(partid < 0 || partid >= xp_max_npartitions);
 
 	spin_lock_irqsave(&part->act_lock, irq_flags);
 
@@ -544,7 +544,7 @@
 	short partid = (short)(u64)dev_id;
 	struct xpc_partition *part = &xpc_partitions[partid];
 
-	DBUG_ON(partid <= 0 || partid >= XP_MAX_PARTITIONS);
+	DBUG_ON(partid < 0 || partid >= xp_max_npartitions);
 
 	if (xpc_part_ref(part)) {
 		xpc_check_for_channel_activity(part);
@@ -815,7 +815,7 @@
 	int wakeup_channel_mgr;
 
 	/* now wait for all callouts to the caller's function to cease */
-	for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) {
+	for (partid = 0; partid < xp_max_npartitions; partid++) {
 		part = &xpc_partitions[partid];
 
 		if (!xpc_part_ref(part))
@@ -895,7 +895,7 @@
 	do {
 		active_part_count = 0;
 
-		for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) {
+		for (partid = 0; partid < xp_max_npartitions; partid++) {
 			part = &xpc_partitions[partid];
 
 			if (xpc_partition_disengaged(part) &&
@@ -956,11 +956,8 @@
 	DBUG_ON(xpc_vars->heartbeating_to_mask != 0);
 
 	if (reason == xpUnloading) {
-		/* 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);
+		(void)unregister_reboot_notifier(&xpc_reboot_notifier);
 	}
 
 	/* close down protections for IPI operations */
@@ -972,6 +969,7 @@
 	if (xpc_sysctl)
 		unregister_sysctl_table(xpc_sysctl);
 
+	kfree(xpc_partitions);
 	kfree(xpc_remote_copy_buffer_base);
 }
 
@@ -1017,7 +1015,7 @@
 
 	xpc_vars->heartbeating_to_mask = 0;	/* indicate we're deactivated */
 
-	for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) {
+	for (partid = 0; partid < xp_max_npartitions; partid++) {
 		part = &xpc_partitions[partid];
 
 		if (!XPC_SUPPORTS_DISENGAGE_REQUEST(part->
@@ -1053,7 +1051,8 @@
 
 		time = rtc_time();
 		if (time >= disengage_request_timeout) {
-			for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) {
+			for (partid = 0; partid < xp_max_npartitions;
+			     partid++) {
 				if (engaged & (1UL << partid)) {
 					dev_info(xpc_part, "disengage from "
 						 "remote partition %d timed "
@@ -1132,18 +1131,26 @@
 	if (!ia64_platform_is("sn2"))
 		return -ENODEV;
 
+	snprintf(xpc_part->bus_id, BUS_ID_SIZE, "part");
+	snprintf(xpc_chan->bus_id, BUS_ID_SIZE, "chan");
+
 	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)
+	if (xpc_remote_copy_buffer == NULL) {
+		dev_err(xpc_part, "can't get memory for remote copy buffer\n");
 		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);
+	xpc_partitions = kzalloc(sizeof(struct xpc_partition) *
+				 xp_max_npartitions, GFP_KERNEL);
+	if (xpc_partitions == NULL) {
+		dev_err(xpc_part, "can't get memory for partition structure\n");
+		ret = -ENOMEM;
+		goto out_1;
+	}
 
 	/*
 	 * The first few fields of each entry of xpc_partitions[] need to
@@ -1153,7 +1160,7 @@
 	 * ENTRIES ARE MEANINGFUL UNTIL AFTER AN ENTRY'S CORRESPONDING
 	 * PARTITION HAS BEEN ACTIVATED.
 	 */
-	for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) {
+	for (partid = 0; partid < xp_max_npartitions; partid++) {
 		part = &xpc_partitions[partid];
 
 		DBUG_ON((u64)part != L1_CACHE_ALIGN((u64)part));
@@ -1173,6 +1180,8 @@
 		atomic_set(&part->references, 0);
 	}
 
+	xpc_sysctl = register_sysctl_table(xpc_sys_dir);
+
 	/*
 	 * Open up protections for IPI operations (and AMO operations on
 	 * Shub 1.1 systems).
@@ -1196,14 +1205,8 @@
 	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;
+		ret = -EBUSY;
+		goto out_2;
 	}
 
 	/*
@@ -1213,16 +1216,9 @@
 	 */
 	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;
+		dev_err(xpc_part, "can't setup our reserved page\n");
+		ret = -EBUSY;
+		goto out_3;
 	}
 
 	/* add ourselves to the reboot_notifier_list */
@@ -1245,25 +1241,8 @@
 	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;
+		ret = -EBUSY;
+		goto out_4;
 	}
 
 	/*
@@ -1290,6 +1269,24 @@
 			  xpc_initiate_partid_to_nasids);
 
 	return 0;
+
+	/* initialization was not successful */
+out_4:
+	/* indicate to others that our reserved page is uninitialized */
+	xpc_rsvd_page->vars_pa = 0;
+	del_timer_sync(&xpc_hb_timer);
+	(void)unregister_die_notifier(&xpc_die_notifier);
+	(void)unregister_reboot_notifier(&xpc_reboot_notifier);
+out_3:
+	free_irq(SGI_XPC_ACTIVATE, NULL);
+out_2:
+	xpc_restrict_IPI_ops();
+	if (xpc_sysctl)
+		unregister_sysctl_table(xpc_sysctl);
+	kfree(xpc_partitions);
+out_1:
+	kfree(xpc_remote_copy_buffer_base);
+	return ret;
 }
 
 module_init(xpc_init);