sgi-xp: prepare xpc_rsvd_page to work on either sn2 or uv hardware

Prepare XPC's reserved page header to work for either sn2 or uv.

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_partition.c b/drivers/misc/sgi-xp/xpc_partition.c
index 6c82f20..1db84cb 100644
--- a/drivers/misc/sgi-xp/xpc_partition.c
+++ b/drivers/misc/sgi-xp/xpc_partition.c
@@ -20,7 +20,6 @@
 #include <linux/cache.h>
 #include <linux/mmzone.h>
 #include <linux/nodemask.h>
-#include <asm/uncached.h>
 #include <asm/sn/intr.h>
 #include <asm/sn/sn_sal.h>
 #include <asm/sn/nodepda.h>
@@ -44,11 +43,10 @@
 struct xpc_rsvd_page *xpc_rsvd_page;
 static u64 *xpc_part_nasids;
 static u64 *xpc_mach_nasids;
-struct xpc_vars *xpc_vars;
-struct xpc_vars_part *xpc_vars_part;
 
-static int xp_nasid_mask_bytes;	/* actual size in bytes of nasid mask */
-static int xp_nasid_mask_words;	/* actual size in words of nasid mask */
+/* >>> next two variables should be 'xpc_' if they remain here */
+static int xp_sizeof_nasid_mask;	/* actual size in bytes of nasid mask */
+int xp_nasid_mask_words;	/* actual size in words of nasid mask */
 
 struct xpc_partition *xpc_partitions;
 
@@ -150,12 +148,10 @@
  * communications.
  */
 struct xpc_rsvd_page *
-xpc_rsvd_page_init(void)
+xpc_setup_rsvd_page(void)
 {
 	struct xpc_rsvd_page *rp;
-	AMO_t *amos_page;
-	u64 rp_pa, nasid_array = 0;
-	int i, ret;
+	u64 rp_pa;
 
 	/* get the local reserved page's address */
 
@@ -168,110 +164,44 @@
 	}
 	rp = (struct xpc_rsvd_page *)__va(rp_pa);
 
-	if (rp->partid != sn_partition_id) {
-		dev_err(xpc_part, "the reserved page's partid of %d should be "
-			"%d\n", rp->partid, sn_partition_id);
+	if (rp->SAL_version < 3) {
+		/* SAL_versions < 3 had a SAL_partid defined as a u8 */
+		rp->SAL_partid &= 0xff;
+	}
+	BUG_ON(rp->SAL_partid != sn_partition_id);
+
+	if (rp->SAL_partid < 0 || rp->SAL_partid >= xp_max_npartitions) {
+		dev_err(xpc_part, "the reserved page's partid of %d is outside "
+			"supported range (< 0 || >= %d)\n", rp->SAL_partid,
+			xp_max_npartitions);
 		return NULL;
 	}
 
 	rp->version = XPC_RP_VERSION;
+	rp->max_npartitions = xp_max_npartitions;
 
 	/* establish the actual sizes of the nasid masks */
 	if (rp->SAL_version == 1) {
 		/* SAL_version 1 didn't set the nasids_size field */
-		rp->nasids_size = 128;
+		rp->SAL_nasids_size = 128;
 	}
-	xp_nasid_mask_bytes = rp->nasids_size;
-	xp_nasid_mask_words = xp_nasid_mask_bytes / 8;
+	xp_sizeof_nasid_mask = rp->SAL_nasids_size;
+	xp_nasid_mask_words = DIV_ROUND_UP(xp_sizeof_nasid_mask,
+					   BYTES_PER_WORD);
 
 	/* setup the pointers to the various items in the reserved page */
 	xpc_part_nasids = XPC_RP_PART_NASIDS(rp);
 	xpc_mach_nasids = XPC_RP_MACH_NASIDS(rp);
-	xpc_vars = XPC_RP_VARS(rp);
-	xpc_vars_part = XPC_RP_VARS_PART(rp);
+
+	if (xpc_rsvd_page_init(rp) != xpSuccess)
+		return NULL;
 
 	/*
-	 * Before clearing xpc_vars, see if a page of AMOs had been previously
-	 * allocated. If not we'll need to allocate one and set permissions
-	 * so that cross-partition AMOs are allowed.
-	 *
-	 * The allocated AMO page needs MCA reporting to remain disabled after
-	 * XPC has unloaded.  To make this work, we keep a copy of the pointer
-	 * to this page (i.e., amos_page) in the struct xpc_vars structure,
-	 * which is pointed to by the reserved page, and re-use that saved copy
-	 * on subsequent loads of XPC. This AMO page is never freed, and its
-	 * memory protections are never restricted.
-	 */
-	amos_page = xpc_vars->amos_page;
-	if (amos_page == NULL) {
-		amos_page = (AMO_t *)TO_AMO(uncached_alloc_page(0, 1));
-		if (amos_page == NULL) {
-			dev_err(xpc_part, "can't allocate page of AMOs\n");
-			return NULL;
-		}
-
-		/*
-		 * Open up AMO-R/W to cpu.  This is done for Shub 1.1 systems
-		 * when xpc_allow_IPI_ops() is called via xpc_hb_init().
-		 */
-		if (!enable_shub_wars_1_1()) {
-			ret = sn_change_memprotect(ia64_tpa((u64)amos_page),
-						   PAGE_SIZE,
-						   SN_MEMPROT_ACCESS_CLASS_1,
-						   &nasid_array);
-			if (ret != 0) {
-				dev_err(xpc_part, "can't change memory "
-					"protections\n");
-				uncached_free_page(__IA64_UNCACHED_OFFSET |
-						   TO_PHYS((u64)amos_page), 1);
-				return NULL;
-			}
-		}
-	} else if (!IS_AMO_ADDRESS((u64)amos_page)) {
-		/*
-		 * EFI's XPBOOT can also set amos_page in the reserved page,
-		 * but it happens to leave it as an uncached physical address
-		 * and we need it to be an uncached virtual, so we'll have to
-		 * convert it.
-		 */
-		if (!IS_AMO_PHYS_ADDRESS((u64)amos_page)) {
-			dev_err(xpc_part, "previously used amos_page address "
-				"is bad = 0x%p\n", (void *)amos_page);
-			return NULL;
-		}
-		amos_page = (AMO_t *)TO_AMO((u64)amos_page);
-	}
-
-	/* clear xpc_vars */
-	memset(xpc_vars, 0, sizeof(struct xpc_vars));
-
-	xpc_vars->version = XPC_V_VERSION;
-	xpc_vars->act_nasid = cpuid_to_nasid(0);
-	xpc_vars->act_phys_cpuid = cpu_physical_id(0);
-	xpc_vars->vars_part_pa = __pa(xpc_vars_part);
-	xpc_vars->amos_page_pa = ia64_tpa((u64)amos_page);
-	xpc_vars->amos_page = amos_page;	/* save for next load of XPC */
-
-	/* clear xpc_vars_part */
-	memset((u64 *)xpc_vars_part, 0, sizeof(struct xpc_vars_part) *
-	       xp_max_npartitions);
-
-	/* initialize the activate IRQ related AMO variables */
-	for (i = 0; i < xp_nasid_mask_words; i++)
-		(void)xpc_IPI_init(XPC_ACTIVATE_IRQ_AMOS + i);
-
-	/* initialize the engaged remote partitions related AMO variables */
-	(void)xpc_IPI_init(XPC_ENGAGED_PARTITIONS_AMO);
-	(void)xpc_IPI_init(XPC_DISENGAGE_REQUEST_AMO);
-
-	/* timestamp of when reserved page was setup by XPC */
-	rp->stamp = CURRENT_TIME;
-
-	/*
+	 * Set timestamp of when reserved page was setup by XPC.
 	 * This signifies to the remote partition that our reserved
 	 * page is initialized.
 	 */
-	rp->vars_pa = __pa(xpc_vars);
+	rp->stamp = CURRENT_TIME;
 
 	return rp;
 }
@@ -465,7 +395,7 @@
 
 	/* pull over the reserved page header and part_nasids mask */
 	ret = xp_remote_memcpy(remote_rp, (void *)*remote_rp_pa,
-			       XPC_RP_HEADER_SIZE + xp_nasid_mask_bytes);
+			       XPC_RP_HEADER_SIZE + xp_sizeof_nasid_mask);
 	if (ret != xpSuccess)
 		return ret;
 
@@ -476,19 +406,28 @@
 			discovered_nasids[i] |= remote_part_nasids[i];
 	}
 
-	/* check that the partid is for another partition */
+	/* check that the partid is valid and is for another partition */
 
-	if (remote_rp->partid < 0 || remote_rp->partid >= xp_max_npartitions)
+	if (remote_rp->SAL_partid < 0 ||
+	    remote_rp->SAL_partid >= xp_max_npartitions) {
 		return xpInvalidPartid;
+	}
 
-	if (remote_rp->partid == sn_partition_id)
+	if (remote_rp->SAL_partid == sn_partition_id)
 		return xpLocalPartid;
 
+	/* see if the rest of the reserved page has been set up by XPC */
+	if (timespec_equal(&remote_rp->stamp, &ZERO_STAMP))
+		return xpRsvdPageNotSet;
+
 	if (XPC_VERSION_MAJOR(remote_rp->version) !=
 	    XPC_VERSION_MAJOR(XPC_RP_VERSION)) {
 		return xpBadVersion;
 	}
 
+	if (remote_rp->max_npartitions <= sn_partition_id)
+		return xpInvalidPartid;
+
 	return xpSuccess;
 }
 
@@ -592,7 +531,7 @@
 	int remote_rp_version;
 	int reactivate = 0;
 	int stamp_diff;
-	struct timespec remote_rp_stamp = { 0, 0 };
+	struct timespec remote_rp_stamp = { 0, 0 }; /*>>> ZERO_STAMP */
 	short partid;
 	struct xpc_partition *part;
 	enum xp_retval ret;
@@ -608,12 +547,12 @@
 		return;
 	}
 
-	remote_vars_pa = remote_rp->vars_pa;
+	remote_vars_pa = remote_rp->sn.vars_pa;
 	remote_rp_version = remote_rp->version;
 	if (XPC_SUPPORTS_RP_STAMP(remote_rp_version))
 		remote_rp_stamp = remote_rp->stamp;
 
-	partid = remote_rp->partid;
+	partid = remote_rp->SAL_partid;
 	part = &xpc_partitions[partid];
 
 	/* pull over the cross partition variables */
@@ -977,7 +916,7 @@
 	enum xp_retval ret;
 
 	remote_rp = xpc_kmalloc_cacheline_aligned(XPC_RP_HEADER_SIZE +
-						  xp_nasid_mask_bytes,
+						  xp_sizeof_nasid_mask,
 						  GFP_KERNEL, &remote_rp_base);
 	if (remote_rp == NULL)
 		return;
@@ -1063,9 +1002,9 @@
 				continue;
 			}
 
-			remote_vars_pa = remote_rp->vars_pa;
+			remote_vars_pa = remote_rp->sn.vars_pa;
 
-			partid = remote_rp->partid;
+			partid = remote_rp->SAL_partid;
 			part = &xpc_partitions[partid];
 
 			/* pull over the cross partition variables */
@@ -1155,5 +1094,5 @@
 	part_nasid_pa = (u64)XPC_RP_PART_NASIDS(part->remote_rp_pa);
 
 	return xp_remote_memcpy(nasid_mask, (void *)part_nasid_pa,
-				xp_nasid_mask_bytes);
+				xp_sizeof_nasid_mask);
 }