diff options
author | Dean Nelson <dcn@sgi.com> | 2008-07-30 01:34:05 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-07-30 12:41:49 -0400 |
commit | 94bd2708d4a95d7da5a1c7c28a063eccd127fb69 (patch) | |
tree | bcc65d3966e240017f8fb355114ec07c906b0b63 /drivers/misc/sgi-xp/xpc_partition.c | |
parent | 908787db9b95f548270af18d83d62b9d2020ca10 (diff) |
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>
Diffstat (limited to 'drivers/misc/sgi-xp/xpc_partition.c')
-rw-r--r-- | drivers/misc/sgi-xp/xpc_partition.c | 149 |
1 files changed, 44 insertions, 105 deletions
diff --git a/drivers/misc/sgi-xp/xpc_partition.c b/drivers/misc/sgi-xp/xpc_partition.c index 6c82f2050974..1db84cb49143 100644 --- a/drivers/misc/sgi-xp/xpc_partition.c +++ b/drivers/misc/sgi-xp/xpc_partition.c | |||
@@ -20,7 +20,6 @@ | |||
20 | #include <linux/cache.h> | 20 | #include <linux/cache.h> |
21 | #include <linux/mmzone.h> | 21 | #include <linux/mmzone.h> |
22 | #include <linux/nodemask.h> | 22 | #include <linux/nodemask.h> |
23 | #include <asm/uncached.h> | ||
24 | #include <asm/sn/intr.h> | 23 | #include <asm/sn/intr.h> |
25 | #include <asm/sn/sn_sal.h> | 24 | #include <asm/sn/sn_sal.h> |
26 | #include <asm/sn/nodepda.h> | 25 | #include <asm/sn/nodepda.h> |
@@ -44,11 +43,10 @@ u64 xpc_prot_vec[MAX_NUMNODES]; | |||
44 | struct xpc_rsvd_page *xpc_rsvd_page; | 43 | struct xpc_rsvd_page *xpc_rsvd_page; |
45 | static u64 *xpc_part_nasids; | 44 | static u64 *xpc_part_nasids; |
46 | static u64 *xpc_mach_nasids; | 45 | static u64 *xpc_mach_nasids; |
47 | struct xpc_vars *xpc_vars; | ||
48 | struct xpc_vars_part *xpc_vars_part; | ||
49 | 46 | ||
50 | static int xp_nasid_mask_bytes; /* actual size in bytes of nasid mask */ | 47 | /* >>> next two variables should be 'xpc_' if they remain here */ |
51 | static int xp_nasid_mask_words; /* actual size in words of nasid mask */ | 48 | static int xp_sizeof_nasid_mask; /* actual size in bytes of nasid mask */ |
49 | int xp_nasid_mask_words; /* actual size in words of nasid mask */ | ||
52 | 50 | ||
53 | struct xpc_partition *xpc_partitions; | 51 | struct xpc_partition *xpc_partitions; |
54 | 52 | ||
@@ -150,12 +148,10 @@ xpc_get_rsvd_page_pa(int nasid) | |||
150 | * communications. | 148 | * communications. |
151 | */ | 149 | */ |
152 | struct xpc_rsvd_page * | 150 | struct xpc_rsvd_page * |
153 | xpc_rsvd_page_init(void) | 151 | xpc_setup_rsvd_page(void) |
154 | { | 152 | { |
155 | struct xpc_rsvd_page *rp; | 153 | struct xpc_rsvd_page *rp; |
156 | AMO_t *amos_page; | 154 | u64 rp_pa; |
157 | u64 rp_pa, nasid_array = 0; | ||
158 | int i, ret; | ||
159 | 155 | ||
160 | /* get the local reserved page's address */ | 156 | /* get the local reserved page's address */ |
161 | 157 | ||
@@ -168,110 +164,44 @@ xpc_rsvd_page_init(void) | |||
168 | } | 164 | } |
169 | rp = (struct xpc_rsvd_page *)__va(rp_pa); | 165 | rp = (struct xpc_rsvd_page *)__va(rp_pa); |
170 | 166 | ||
171 | if (rp->partid != sn_partition_id) { | 167 | if (rp->SAL_version < 3) { |
172 | dev_err(xpc_part, "the reserved page's partid of %d should be " | 168 | /* SAL_versions < 3 had a SAL_partid defined as a u8 */ |
173 | "%d\n", rp->partid, sn_partition_id); | 169 | rp->SAL_partid &= 0xff; |
170 | } | ||
171 | BUG_ON(rp->SAL_partid != sn_partition_id); | ||
172 | |||
173 | if (rp->SAL_partid < 0 || rp->SAL_partid >= xp_max_npartitions) { | ||
174 | dev_err(xpc_part, "the reserved page's partid of %d is outside " | ||
175 | "supported range (< 0 || >= %d)\n", rp->SAL_partid, | ||
176 | xp_max_npartitions); | ||
174 | return NULL; | 177 | return NULL; |
175 | } | 178 | } |
176 | 179 | ||
177 | rp->version = XPC_RP_VERSION; | 180 | rp->version = XPC_RP_VERSION; |
181 | rp->max_npartitions = xp_max_npartitions; | ||
178 | 182 | ||
179 | /* establish the actual sizes of the nasid masks */ | 183 | /* establish the actual sizes of the nasid masks */ |
180 | if (rp->SAL_version == 1) { | 184 | if (rp->SAL_version == 1) { |
181 | /* SAL_version 1 didn't set the nasids_size field */ | 185 | /* SAL_version 1 didn't set the nasids_size field */ |
182 | rp->nasids_size = 128; | 186 | rp->SAL_nasids_size = 128; |
183 | } | 187 | } |
184 | xp_nasid_mask_bytes = rp->nasids_size; | 188 | xp_sizeof_nasid_mask = rp->SAL_nasids_size; |
185 | xp_nasid_mask_words = xp_nasid_mask_bytes / 8; | 189 | xp_nasid_mask_words = DIV_ROUND_UP(xp_sizeof_nasid_mask, |
190 | BYTES_PER_WORD); | ||
186 | 191 | ||
187 | /* setup the pointers to the various items in the reserved page */ | 192 | /* setup the pointers to the various items in the reserved page */ |
188 | xpc_part_nasids = XPC_RP_PART_NASIDS(rp); | 193 | xpc_part_nasids = XPC_RP_PART_NASIDS(rp); |
189 | xpc_mach_nasids = XPC_RP_MACH_NASIDS(rp); | 194 | xpc_mach_nasids = XPC_RP_MACH_NASIDS(rp); |
190 | xpc_vars = XPC_RP_VARS(rp); | ||
191 | xpc_vars_part = XPC_RP_VARS_PART(rp); | ||
192 | 195 | ||
193 | /* | 196 | if (xpc_rsvd_page_init(rp) != xpSuccess) |
194 | * Before clearing xpc_vars, see if a page of AMOs had been previously | 197 | return NULL; |
195 | * allocated. If not we'll need to allocate one and set permissions | ||
196 | * so that cross-partition AMOs are allowed. | ||
197 | * | ||
198 | * The allocated AMO page needs MCA reporting to remain disabled after | ||
199 | * XPC has unloaded. To make this work, we keep a copy of the pointer | ||
200 | * to this page (i.e., amos_page) in the struct xpc_vars structure, | ||
201 | * which is pointed to by the reserved page, and re-use that saved copy | ||
202 | * on subsequent loads of XPC. This AMO page is never freed, and its | ||
203 | * memory protections are never restricted. | ||
204 | */ | ||
205 | amos_page = xpc_vars->amos_page; | ||
206 | if (amos_page == NULL) { | ||
207 | amos_page = (AMO_t *)TO_AMO(uncached_alloc_page(0, 1)); | ||
208 | if (amos_page == NULL) { | ||
209 | dev_err(xpc_part, "can't allocate page of AMOs\n"); | ||
210 | return NULL; | ||
211 | } | ||
212 | |||
213 | /* | ||
214 | * Open up AMO-R/W to cpu. This is done for Shub 1.1 systems | ||
215 | * when xpc_allow_IPI_ops() is called via xpc_hb_init(). | ||
216 | */ | ||
217 | if (!enable_shub_wars_1_1()) { | ||
218 | ret = sn_change_memprotect(ia64_tpa((u64)amos_page), | ||
219 | PAGE_SIZE, | ||
220 | SN_MEMPROT_ACCESS_CLASS_1, | ||
221 | &nasid_array); | ||
222 | if (ret != 0) { | ||
223 | dev_err(xpc_part, "can't change memory " | ||
224 | "protections\n"); | ||
225 | uncached_free_page(__IA64_UNCACHED_OFFSET | | ||
226 | TO_PHYS((u64)amos_page), 1); | ||
227 | return NULL; | ||
228 | } | ||
229 | } | ||
230 | } else if (!IS_AMO_ADDRESS((u64)amos_page)) { | ||
231 | /* | ||
232 | * EFI's XPBOOT can also set amos_page in the reserved page, | ||
233 | * but it happens to leave it as an uncached physical address | ||
234 | * and we need it to be an uncached virtual, so we'll have to | ||
235 | * convert it. | ||
236 | */ | ||
237 | if (!IS_AMO_PHYS_ADDRESS((u64)amos_page)) { | ||
238 | dev_err(xpc_part, "previously used amos_page address " | ||
239 | "is bad = 0x%p\n", (void *)amos_page); | ||
240 | return NULL; | ||
241 | } | ||
242 | amos_page = (AMO_t *)TO_AMO((u64)amos_page); | ||
243 | } | ||
244 | |||
245 | /* clear xpc_vars */ | ||
246 | memset(xpc_vars, 0, sizeof(struct xpc_vars)); | ||
247 | |||
248 | xpc_vars->version = XPC_V_VERSION; | ||
249 | xpc_vars->act_nasid = cpuid_to_nasid(0); | ||
250 | xpc_vars->act_phys_cpuid = cpu_physical_id(0); | ||
251 | xpc_vars->vars_part_pa = __pa(xpc_vars_part); | ||
252 | xpc_vars->amos_page_pa = ia64_tpa((u64)amos_page); | ||
253 | xpc_vars->amos_page = amos_page; /* save for next load of XPC */ | ||
254 | |||
255 | /* clear xpc_vars_part */ | ||
256 | memset((u64 *)xpc_vars_part, 0, sizeof(struct xpc_vars_part) * | ||
257 | xp_max_npartitions); | ||
258 | |||
259 | /* initialize the activate IRQ related AMO variables */ | ||
260 | for (i = 0; i < xp_nasid_mask_words; i++) | ||
261 | (void)xpc_IPI_init(XPC_ACTIVATE_IRQ_AMOS + i); | ||
262 | |||
263 | /* initialize the engaged remote partitions related AMO variables */ | ||
264 | (void)xpc_IPI_init(XPC_ENGAGED_PARTITIONS_AMO); | ||
265 | (void)xpc_IPI_init(XPC_DISENGAGE_REQUEST_AMO); | ||
266 | |||
267 | /* timestamp of when reserved page was setup by XPC */ | ||
268 | rp->stamp = CURRENT_TIME; | ||
269 | 198 | ||
270 | /* | 199 | /* |
200 | * Set timestamp of when reserved page was setup by XPC. | ||
271 | * This signifies to the remote partition that our reserved | 201 | * This signifies to the remote partition that our reserved |
272 | * page is initialized. | 202 | * page is initialized. |
273 | */ | 203 | */ |
274 | rp->vars_pa = __pa(xpc_vars); | 204 | rp->stamp = CURRENT_TIME; |
275 | 205 | ||
276 | return rp; | 206 | return rp; |
277 | } | 207 | } |
@@ -465,7 +395,7 @@ xpc_get_remote_rp(int nasid, u64 *discovered_nasids, | |||
465 | 395 | ||
466 | /* pull over the reserved page header and part_nasids mask */ | 396 | /* pull over the reserved page header and part_nasids mask */ |
467 | ret = xp_remote_memcpy(remote_rp, (void *)*remote_rp_pa, | 397 | ret = xp_remote_memcpy(remote_rp, (void *)*remote_rp_pa, |
468 | XPC_RP_HEADER_SIZE + xp_nasid_mask_bytes); | 398 | XPC_RP_HEADER_SIZE + xp_sizeof_nasid_mask); |
469 | if (ret != xpSuccess) | 399 | if (ret != xpSuccess) |
470 | return ret; | 400 | return ret; |
471 | 401 | ||
@@ -476,19 +406,28 @@ xpc_get_remote_rp(int nasid, u64 *discovered_nasids, | |||
476 | discovered_nasids[i] |= remote_part_nasids[i]; | 406 | discovered_nasids[i] |= remote_part_nasids[i]; |
477 | } | 407 | } |
478 | 408 | ||
479 | /* check that the partid is for another partition */ | 409 | /* check that the partid is valid and is for another partition */ |
480 | 410 | ||
481 | if (remote_rp->partid < 0 || remote_rp->partid >= xp_max_npartitions) | 411 | if (remote_rp->SAL_partid < 0 || |
412 | remote_rp->SAL_partid >= xp_max_npartitions) { | ||
482 | return xpInvalidPartid; | 413 | return xpInvalidPartid; |
414 | } | ||
483 | 415 | ||
484 | if (remote_rp->partid == sn_partition_id) | 416 | if (remote_rp->SAL_partid == sn_partition_id) |
485 | return xpLocalPartid; | 417 | return xpLocalPartid; |
486 | 418 | ||
419 | /* see if the rest of the reserved page has been set up by XPC */ | ||
420 | if (timespec_equal(&remote_rp->stamp, &ZERO_STAMP)) | ||
421 | return xpRsvdPageNotSet; | ||
422 | |||
487 | if (XPC_VERSION_MAJOR(remote_rp->version) != | 423 | if (XPC_VERSION_MAJOR(remote_rp->version) != |
488 | XPC_VERSION_MAJOR(XPC_RP_VERSION)) { | 424 | XPC_VERSION_MAJOR(XPC_RP_VERSION)) { |
489 | return xpBadVersion; | 425 | return xpBadVersion; |
490 | } | 426 | } |
491 | 427 | ||
428 | if (remote_rp->max_npartitions <= sn_partition_id) | ||
429 | return xpInvalidPartid; | ||
430 | |||
492 | return xpSuccess; | 431 | return xpSuccess; |
493 | } | 432 | } |
494 | 433 | ||
@@ -592,7 +531,7 @@ xpc_identify_act_IRQ_req(int nasid) | |||
592 | int remote_rp_version; | 531 | int remote_rp_version; |
593 | int reactivate = 0; | 532 | int reactivate = 0; |
594 | int stamp_diff; | 533 | int stamp_diff; |
595 | struct timespec remote_rp_stamp = { 0, 0 }; | 534 | struct timespec remote_rp_stamp = { 0, 0 }; /*>>> ZERO_STAMP */ |
596 | short partid; | 535 | short partid; |
597 | struct xpc_partition *part; | 536 | struct xpc_partition *part; |
598 | enum xp_retval ret; | 537 | enum xp_retval ret; |
@@ -608,12 +547,12 @@ xpc_identify_act_IRQ_req(int nasid) | |||
608 | return; | 547 | return; |
609 | } | 548 | } |
610 | 549 | ||
611 | remote_vars_pa = remote_rp->vars_pa; | 550 | remote_vars_pa = remote_rp->sn.vars_pa; |
612 | remote_rp_version = remote_rp->version; | 551 | remote_rp_version = remote_rp->version; |
613 | if (XPC_SUPPORTS_RP_STAMP(remote_rp_version)) | 552 | if (XPC_SUPPORTS_RP_STAMP(remote_rp_version)) |
614 | remote_rp_stamp = remote_rp->stamp; | 553 | remote_rp_stamp = remote_rp->stamp; |
615 | 554 | ||
616 | partid = remote_rp->partid; | 555 | partid = remote_rp->SAL_partid; |
617 | part = &xpc_partitions[partid]; | 556 | part = &xpc_partitions[partid]; |
618 | 557 | ||
619 | /* pull over the cross partition variables */ | 558 | /* pull over the cross partition variables */ |
@@ -977,7 +916,7 @@ xpc_discovery(void) | |||
977 | enum xp_retval ret; | 916 | enum xp_retval ret; |
978 | 917 | ||
979 | remote_rp = xpc_kmalloc_cacheline_aligned(XPC_RP_HEADER_SIZE + | 918 | remote_rp = xpc_kmalloc_cacheline_aligned(XPC_RP_HEADER_SIZE + |
980 | xp_nasid_mask_bytes, | 919 | xp_sizeof_nasid_mask, |
981 | GFP_KERNEL, &remote_rp_base); | 920 | GFP_KERNEL, &remote_rp_base); |
982 | if (remote_rp == NULL) | 921 | if (remote_rp == NULL) |
983 | return; | 922 | return; |
@@ -1063,9 +1002,9 @@ xpc_discovery(void) | |||
1063 | continue; | 1002 | continue; |
1064 | } | 1003 | } |
1065 | 1004 | ||
1066 | remote_vars_pa = remote_rp->vars_pa; | 1005 | remote_vars_pa = remote_rp->sn.vars_pa; |
1067 | 1006 | ||
1068 | partid = remote_rp->partid; | 1007 | partid = remote_rp->SAL_partid; |
1069 | part = &xpc_partitions[partid]; | 1008 | part = &xpc_partitions[partid]; |
1070 | 1009 | ||
1071 | /* pull over the cross partition variables */ | 1010 | /* pull over the cross partition variables */ |
@@ -1155,5 +1094,5 @@ xpc_initiate_partid_to_nasids(short partid, void *nasid_mask) | |||
1155 | part_nasid_pa = (u64)XPC_RP_PART_NASIDS(part->remote_rp_pa); | 1094 | part_nasid_pa = (u64)XPC_RP_PART_NASIDS(part->remote_rp_pa); |
1156 | 1095 | ||
1157 | return xp_remote_memcpy(nasid_mask, (void *)part_nasid_pa, | 1096 | return xp_remote_memcpy(nasid_mask, (void *)part_nasid_pa, |
1158 | xp_nasid_mask_bytes); | 1097 | xp_sizeof_nasid_mask); |
1159 | } | 1098 | } |