Commit | Line | Data |
---|---|---|
89eb8eb9 DN |
1 | /* |
2 | * This file is subject to the terms and conditions of the GNU General Public | |
3 | * License. See the file "COPYING" in the main directory of this archive | |
4 | * for more details. | |
5 | * | |
45d9ca49 | 6 | * Copyright (c) 2004-2008 Silicon Graphics, Inc. All Rights Reserved. |
89eb8eb9 DN |
7 | */ |
8 | ||
89eb8eb9 DN |
9 | /* |
10 | * Cross Partition Communication (XPC) partition support. | |
11 | * | |
12 | * This is the part of XPC that detects the presence/absence of | |
13 | * other partitions. It provides a heartbeat and monitors the | |
14 | * heartbeats of other partitions. | |
15 | * | |
16 | */ | |
17 | ||
89eb8eb9 DN |
18 | #include <linux/kernel.h> |
19 | #include <linux/sysctl.h> | |
20 | #include <linux/cache.h> | |
21 | #include <linux/mmzone.h> | |
22 | #include <linux/nodemask.h> | |
89eb8eb9 DN |
23 | #include <asm/sn/intr.h> |
24 | #include <asm/sn/sn_sal.h> | |
25 | #include <asm/sn/nodepda.h> | |
26 | #include <asm/sn/addrs.h> | |
45d9ca49 | 27 | #include "xpc.h" |
89eb8eb9 | 28 | |
89eb8eb9 DN |
29 | /* XPC is exiting flag */ |
30 | int xpc_exiting; | |
31 | ||
4b38fcd4 | 32 | /* this partition's reserved page pointers */ |
89eb8eb9 | 33 | struct xpc_rsvd_page *xpc_rsvd_page; |
4b38fcd4 | 34 | static u64 *xpc_part_nasids; |
33ba3c77 | 35 | u64 *xpc_mach_nasids; |
89eb8eb9 | 36 | |
ee6665e3 DN |
37 | static int xpc_sizeof_nasid_mask; /* actual size in bytes of nasid mask */ |
38 | int xpc_nasid_mask_words; /* actual size in words of nasid mask */ | |
4b38fcd4 | 39 | |
bc63d387 | 40 | struct xpc_partition *xpc_partitions; |
89eb8eb9 | 41 | |
7aa6ba41 JS |
42 | /* |
43 | * Guarantee that the kmalloc'd memory is cacheline aligned. | |
44 | */ | |
7682a4c6 | 45 | void * |
7aa6ba41 JS |
46 | xpc_kmalloc_cacheline_aligned(size_t size, gfp_t flags, void **base) |
47 | { | |
48 | /* see if kmalloc will give us cachline aligned memory by default */ | |
49 | *base = kmalloc(size, flags); | |
2c2b94f9 | 50 | if (*base == NULL) |
7aa6ba41 | 51 | return NULL; |
2c2b94f9 DN |
52 | |
53 | if ((u64)*base == L1_CACHE_ALIGN((u64)*base)) | |
7aa6ba41 | 54 | return *base; |
2c2b94f9 | 55 | |
7aa6ba41 JS |
56 | kfree(*base); |
57 | ||
58 | /* nope, we'll have to do it ourselves */ | |
59 | *base = kmalloc(size + L1_CACHE_BYTES, flags); | |
2c2b94f9 | 60 | if (*base == NULL) |
7aa6ba41 | 61 | return NULL; |
2c2b94f9 | 62 | |
4a3ad2dd | 63 | return (void *)L1_CACHE_ALIGN((u64)*base); |
7aa6ba41 JS |
64 | } |
65 | ||
89eb8eb9 DN |
66 | /* |
67 | * Given a nasid, get the physical address of the partition's reserved page | |
68 | * for that nasid. This function returns 0 on any error. | |
69 | */ | |
70 | static u64 | |
27929029 | 71 | xpc_get_rsvd_page_pa(int nasid) |
89eb8eb9 | 72 | { |
908787db | 73 | enum xp_retval ret; |
89eb8eb9 DN |
74 | s64 status; |
75 | u64 cookie = 0; | |
76 | u64 rp_pa = nasid; /* seed with nasid */ | |
77 | u64 len = 0; | |
27929029 DN |
78 | u64 buf = buf; |
79 | u64 buf_len = 0; | |
80 | void *buf_base = NULL; | |
89eb8eb9 | 81 | |
89eb8eb9 DN |
82 | while (1) { |
83 | ||
84 | status = sn_partition_reserved_page_pa(buf, &cookie, &rp_pa, | |
4a3ad2dd | 85 | &len); |
89eb8eb9 DN |
86 | |
87 | dev_dbg(xpc_part, "SAL returned with status=%li, cookie=" | |
88 | "0x%016lx, address=0x%016lx, len=0x%016lx\n", | |
89 | status, cookie, rp_pa, len); | |
90 | ||
2c2b94f9 | 91 | if (status != SALRET_MORE_PASSES) |
89eb8eb9 | 92 | break; |
89eb8eb9 | 93 | |
908787db | 94 | /* >>> L1_CACHE_ALIGN() is only a sn2-bte_copy requirement */ |
27929029 | 95 | if (L1_CACHE_ALIGN(len) > buf_len) { |
cbf283c0 | 96 | kfree(buf_base); |
27929029 | 97 | buf_len = L1_CACHE_ALIGN(len); |
4a3ad2dd DN |
98 | buf = (u64)xpc_kmalloc_cacheline_aligned(buf_len, |
99 | GFP_KERNEL, | |
100 | &buf_base); | |
27929029 DN |
101 | if (buf_base == NULL) { |
102 | dev_err(xpc_part, "unable to kmalloc " | |
103 | "len=0x%016lx\n", buf_len); | |
104 | status = SALRET_ERROR; | |
105 | break; | |
106 | } | |
89eb8eb9 DN |
107 | } |
108 | ||
908787db DN |
109 | ret = xp_remote_memcpy((void *)buf, (void *)rp_pa, buf_len); |
110 | if (ret != xpSuccess) { | |
111 | dev_dbg(xpc_part, "xp_remote_memcpy failed %d\n", ret); | |
89eb8eb9 DN |
112 | status = SALRET_ERROR; |
113 | break; | |
114 | } | |
115 | } | |
116 | ||
cbf283c0 | 117 | kfree(buf_base); |
27929029 | 118 | |
2c2b94f9 | 119 | if (status != SALRET_OK) |
89eb8eb9 | 120 | rp_pa = 0; |
2c2b94f9 | 121 | |
89eb8eb9 DN |
122 | dev_dbg(xpc_part, "reserved page at phys address 0x%016lx\n", rp_pa); |
123 | return rp_pa; | |
124 | } | |
125 | ||
89eb8eb9 DN |
126 | /* |
127 | * Fill the partition reserved page with the information needed by | |
128 | * other partitions to discover we are alive and establish initial | |
129 | * communications. | |
130 | */ | |
131 | struct xpc_rsvd_page * | |
94bd2708 | 132 | xpc_setup_rsvd_page(void) |
89eb8eb9 DN |
133 | { |
134 | struct xpc_rsvd_page *rp; | |
94bd2708 | 135 | u64 rp_pa; |
aaa3cd69 | 136 | unsigned long new_stamp; |
89eb8eb9 | 137 | |
89eb8eb9 DN |
138 | /* get the local reserved page's address */ |
139 | ||
27929029 DN |
140 | preempt_disable(); |
141 | rp_pa = xpc_get_rsvd_page_pa(cpuid_to_nasid(smp_processor_id())); | |
142 | preempt_enable(); | |
89eb8eb9 DN |
143 | if (rp_pa == 0) { |
144 | dev_err(xpc_part, "SAL failed to locate the reserved page\n"); | |
145 | return NULL; | |
146 | } | |
4a3ad2dd | 147 | rp = (struct xpc_rsvd_page *)__va(rp_pa); |
89eb8eb9 | 148 | |
94bd2708 DN |
149 | if (rp->SAL_version < 3) { |
150 | /* SAL_versions < 3 had a SAL_partid defined as a u8 */ | |
151 | rp->SAL_partid &= 0xff; | |
152 | } | |
153 | BUG_ON(rp->SAL_partid != sn_partition_id); | |
154 | ||
155 | if (rp->SAL_partid < 0 || rp->SAL_partid >= xp_max_npartitions) { | |
156 | dev_err(xpc_part, "the reserved page's partid of %d is outside " | |
157 | "supported range (< 0 || >= %d)\n", rp->SAL_partid, | |
158 | xp_max_npartitions); | |
89eb8eb9 DN |
159 | return NULL; |
160 | } | |
161 | ||
162 | rp->version = XPC_RP_VERSION; | |
94bd2708 | 163 | rp->max_npartitions = xp_max_npartitions; |
89eb8eb9 | 164 | |
4b38fcd4 DN |
165 | /* establish the actual sizes of the nasid masks */ |
166 | if (rp->SAL_version == 1) { | |
167 | /* SAL_version 1 didn't set the nasids_size field */ | |
94bd2708 | 168 | rp->SAL_nasids_size = 128; |
4b38fcd4 | 169 | } |
ee6665e3 DN |
170 | xpc_sizeof_nasid_mask = rp->SAL_nasids_size; |
171 | xpc_nasid_mask_words = DIV_ROUND_UP(xpc_sizeof_nasid_mask, | |
172 | BYTES_PER_WORD); | |
4b38fcd4 DN |
173 | |
174 | /* setup the pointers to the various items in the reserved page */ | |
175 | xpc_part_nasids = XPC_RP_PART_NASIDS(rp); | |
176 | xpc_mach_nasids = XPC_RP_MACH_NASIDS(rp); | |
89eb8eb9 | 177 | |
94bd2708 DN |
178 | if (xpc_rsvd_page_init(rp) != xpSuccess) |
179 | return NULL; | |
89eb8eb9 DN |
180 | |
181 | /* | |
94bd2708 | 182 | * Set timestamp of when reserved page was setup by XPC. |
89eb8eb9 DN |
183 | * This signifies to the remote partition that our reserved |
184 | * page is initialized. | |
185 | */ | |
aaa3cd69 DN |
186 | new_stamp = jiffies; |
187 | if (new_stamp == 0 || new_stamp == rp->stamp) | |
188 | new_stamp++; | |
189 | rp->stamp = new_stamp; | |
89eb8eb9 DN |
190 | |
191 | return rp; | |
192 | } | |
193 | ||
89eb8eb9 | 194 | /* |
4b38fcd4 | 195 | * Get a copy of a portion of the remote partition's rsvd page. |
89eb8eb9 DN |
196 | * |
197 | * remote_rp points to a buffer that is cacheline aligned for BTE copies and | |
4b38fcd4 DN |
198 | * is large enough to contain a copy of their reserved page header and |
199 | * part_nasids mask. | |
89eb8eb9 | 200 | */ |
33ba3c77 | 201 | enum xp_retval |
89eb8eb9 | 202 | xpc_get_remote_rp(int nasid, u64 *discovered_nasids, |
4a3ad2dd | 203 | struct xpc_rsvd_page *remote_rp, u64 *remote_rp_pa) |
89eb8eb9 | 204 | { |
908787db DN |
205 | int i; |
206 | enum xp_retval ret; | |
89eb8eb9 | 207 | |
89eb8eb9 DN |
208 | /* get the reserved page's physical address */ |
209 | ||
27929029 | 210 | *remote_rp_pa = xpc_get_rsvd_page_pa(nasid); |
2c2b94f9 | 211 | if (*remote_rp_pa == 0) |
65c17b80 | 212 | return xpNoRsvdPageAddr; |
89eb8eb9 | 213 | |
4b38fcd4 | 214 | /* pull over the reserved page header and part_nasids mask */ |
908787db | 215 | ret = xp_remote_memcpy(remote_rp, (void *)*remote_rp_pa, |
ee6665e3 | 216 | XPC_RP_HEADER_SIZE + xpc_sizeof_nasid_mask); |
908787db DN |
217 | if (ret != xpSuccess) |
218 | return ret; | |
89eb8eb9 | 219 | |
89eb8eb9 | 220 | if (discovered_nasids != NULL) { |
4b38fcd4 DN |
221 | u64 *remote_part_nasids = XPC_RP_PART_NASIDS(remote_rp); |
222 | ||
ee6665e3 | 223 | for (i = 0; i < xpc_nasid_mask_words; i++) |
4b38fcd4 | 224 | discovered_nasids[i] |= remote_part_nasids[i]; |
89eb8eb9 DN |
225 | } |
226 | ||
aaa3cd69 DN |
227 | /* see if the reserved page has been set up by XPC */ |
228 | if (remote_rp->stamp == 0) | |
94bd2708 DN |
229 | return xpRsvdPageNotSet; |
230 | ||
89eb8eb9 | 231 | if (XPC_VERSION_MAJOR(remote_rp->version) != |
4a3ad2dd | 232 | XPC_VERSION_MAJOR(XPC_RP_VERSION)) { |
65c17b80 | 233 | return xpBadVersion; |
89eb8eb9 DN |
234 | } |
235 | ||
a47d5dac | 236 | /* check that both remote and local partids are valid for each side */ |
aaa3cd69 DN |
237 | if (remote_rp->SAL_partid < 0 || |
238 | remote_rp->SAL_partid >= xp_max_npartitions || | |
239 | remote_rp->max_npartitions <= sn_partition_id) { | |
94bd2708 | 240 | return xpInvalidPartid; |
aaa3cd69 DN |
241 | } |
242 | ||
243 | if (remote_rp->SAL_partid == sn_partition_id) | |
244 | return xpLocalPartid; | |
94bd2708 | 245 | |
65c17b80 | 246 | return xpSuccess; |
89eb8eb9 DN |
247 | } |
248 | ||
a607c389 | 249 | /* |
a47d5dac DN |
250 | * See if the other side has responded to a partition deactivate request |
251 | * from us. Though we requested the remote partition to deactivate with regard | |
252 | * to us, we really only need to wait for the other side to disengage from us. | |
a607c389 DN |
253 | */ |
254 | int | |
255 | xpc_partition_disengaged(struct xpc_partition *part) | |
256 | { | |
64d032ba | 257 | short partid = XPC_PARTID(part); |
a607c389 DN |
258 | int disengaged; |
259 | ||
a47d5dac DN |
260 | disengaged = !xpc_partition_engaged(partid); |
261 | if (part->disengage_timeout) { | |
a607c389 | 262 | if (!disengaged) { |
a47d5dac | 263 | if (time_is_after_jiffies(part->disengage_timeout)) { |
a607c389 DN |
264 | /* timelimit hasn't been reached yet */ |
265 | return 0; | |
266 | } | |
267 | ||
268 | /* | |
a47d5dac | 269 | * Other side hasn't responded to our deactivate |
a607c389 DN |
270 | * request in a timely fashion, so assume it's dead. |
271 | */ | |
272 | ||
a47d5dac DN |
273 | dev_info(xpc_part, "deactivate request to remote " |
274 | "partition %d timed out\n", partid); | |
275 | xpc_disengage_timedout = 1; | |
276 | xpc_assume_partition_disengaged(partid); | |
a607c389 DN |
277 | disengaged = 1; |
278 | } | |
a47d5dac | 279 | part->disengage_timeout = 0; |
a607c389 DN |
280 | |
281 | /* cancel the timer function, provided it's not us */ | |
a47d5dac DN |
282 | if (!in_interrupt()) |
283 | del_singleshot_timer_sync(&part->disengage_timer); | |
a607c389 DN |
284 | |
285 | DBUG_ON(part->act_state != XPC_P_DEACTIVATING && | |
4a3ad2dd | 286 | part->act_state != XPC_P_INACTIVE); |
2c2b94f9 | 287 | if (part->act_state != XPC_P_INACTIVE) |
a607c389 | 288 | xpc_wakeup_channel_mgr(part); |
a607c389 | 289 | |
a47d5dac | 290 | xpc_cancel_partition_deactivation_request(part); |
a607c389 DN |
291 | } |
292 | return disengaged; | |
293 | } | |
294 | ||
89eb8eb9 DN |
295 | /* |
296 | * Mark specified partition as active. | |
297 | */ | |
65c17b80 | 298 | enum xp_retval |
89eb8eb9 DN |
299 | xpc_mark_partition_active(struct xpc_partition *part) |
300 | { | |
301 | unsigned long irq_flags; | |
65c17b80 | 302 | enum xp_retval ret; |
89eb8eb9 | 303 | |
89eb8eb9 DN |
304 | dev_dbg(xpc_part, "setting partition %d to ACTIVE\n", XPC_PARTID(part)); |
305 | ||
306 | spin_lock_irqsave(&part->act_lock, irq_flags); | |
307 | if (part->act_state == XPC_P_ACTIVATING) { | |
308 | part->act_state = XPC_P_ACTIVE; | |
65c17b80 | 309 | ret = xpSuccess; |
89eb8eb9 | 310 | } else { |
65c17b80 | 311 | DBUG_ON(part->reason == xpSuccess); |
89eb8eb9 DN |
312 | ret = part->reason; |
313 | } | |
314 | spin_unlock_irqrestore(&part->act_lock, irq_flags); | |
315 | ||
316 | return ret; | |
317 | } | |
318 | ||
89eb8eb9 | 319 | /* |
a47d5dac | 320 | * Start the process of deactivating the specified partition. |
89eb8eb9 DN |
321 | */ |
322 | void | |
323 | xpc_deactivate_partition(const int line, struct xpc_partition *part, | |
65c17b80 | 324 | enum xp_retval reason) |
89eb8eb9 DN |
325 | { |
326 | unsigned long irq_flags; | |
89eb8eb9 | 327 | |
89eb8eb9 DN |
328 | spin_lock_irqsave(&part->act_lock, irq_flags); |
329 | ||
330 | if (part->act_state == XPC_P_INACTIVE) { | |
331 | XPC_SET_REASON(part, reason, line); | |
332 | spin_unlock_irqrestore(&part->act_lock, irq_flags); | |
65c17b80 | 333 | if (reason == xpReactivating) { |
89eb8eb9 | 334 | /* we interrupt ourselves to reactivate partition */ |
a47d5dac | 335 | xpc_request_partition_reactivation(part); |
89eb8eb9 DN |
336 | } |
337 | return; | |
338 | } | |
339 | if (part->act_state == XPC_P_DEACTIVATING) { | |
65c17b80 DN |
340 | if ((part->reason == xpUnloading && reason != xpUnloading) || |
341 | reason == xpReactivating) { | |
89eb8eb9 DN |
342 | XPC_SET_REASON(part, reason, line); |
343 | } | |
344 | spin_unlock_irqrestore(&part->act_lock, irq_flags); | |
345 | return; | |
346 | } | |
347 | ||
348 | part->act_state = XPC_P_DEACTIVATING; | |
349 | XPC_SET_REASON(part, reason, line); | |
350 | ||
351 | spin_unlock_irqrestore(&part->act_lock, irq_flags); | |
352 | ||
a47d5dac DN |
353 | /* ask remote partition to deactivate with regard to us */ |
354 | xpc_request_partition_deactivation(part); | |
89eb8eb9 | 355 | |
a47d5dac DN |
356 | /* set a timelimit on the disengage phase of the deactivation request */ |
357 | part->disengage_timeout = jiffies + (xpc_disengage_timelimit * HZ); | |
358 | part->disengage_timer.expires = part->disengage_timeout; | |
359 | add_timer(&part->disengage_timer); | |
89eb8eb9 | 360 | |
e54af724 DN |
361 | dev_dbg(xpc_part, "bringing partition %d down, reason = %d\n", |
362 | XPC_PARTID(part), reason); | |
89eb8eb9 | 363 | |
a607c389 | 364 | xpc_partition_going_down(part, reason); |
89eb8eb9 DN |
365 | } |
366 | ||
89eb8eb9 | 367 | /* |
a607c389 | 368 | * Mark specified partition as inactive. |
89eb8eb9 DN |
369 | */ |
370 | void | |
371 | xpc_mark_partition_inactive(struct xpc_partition *part) | |
372 | { | |
373 | unsigned long irq_flags; | |
374 | ||
89eb8eb9 DN |
375 | dev_dbg(xpc_part, "setting partition %d to INACTIVE\n", |
376 | XPC_PARTID(part)); | |
377 | ||
378 | spin_lock_irqsave(&part->act_lock, irq_flags); | |
379 | part->act_state = XPC_P_INACTIVE; | |
380 | spin_unlock_irqrestore(&part->act_lock, irq_flags); | |
381 | part->remote_rp_pa = 0; | |
382 | } | |
383 | ||
89eb8eb9 DN |
384 | /* |
385 | * SAL has provided a partition and machine mask. The partition mask | |
386 | * contains a bit for each even nasid in our partition. The machine | |
387 | * mask contains a bit for each even nasid in the entire machine. | |
388 | * | |
389 | * Using those two bit arrays, we can determine which nasids are | |
390 | * known in the machine. Each should also have a reserved page | |
391 | * initialized if they are available for partitioning. | |
392 | */ | |
393 | void | |
394 | xpc_discovery(void) | |
395 | { | |
396 | void *remote_rp_base; | |
397 | struct xpc_rsvd_page *remote_rp; | |
a607c389 | 398 | u64 remote_rp_pa; |
89eb8eb9 | 399 | int region; |
4b38fcd4 | 400 | int region_size; |
89eb8eb9 DN |
401 | int max_regions; |
402 | int nasid; | |
403 | struct xpc_rsvd_page *rp; | |
89eb8eb9 | 404 | u64 *discovered_nasids; |
65c17b80 | 405 | enum xp_retval ret; |
89eb8eb9 | 406 | |
4b38fcd4 | 407 | remote_rp = xpc_kmalloc_cacheline_aligned(XPC_RP_HEADER_SIZE + |
ee6665e3 | 408 | xpc_sizeof_nasid_mask, |
4a3ad2dd | 409 | GFP_KERNEL, &remote_rp_base); |
2c2b94f9 | 410 | if (remote_rp == NULL) |
89eb8eb9 | 411 | return; |
2c2b94f9 | 412 | |
ee6665e3 | 413 | discovered_nasids = kzalloc(sizeof(u64) * xpc_nasid_mask_words, |
4a3ad2dd | 414 | GFP_KERNEL); |
89eb8eb9 DN |
415 | if (discovered_nasids == NULL) { |
416 | kfree(remote_rp_base); | |
417 | return; | |
418 | } | |
89eb8eb9 | 419 | |
4a3ad2dd | 420 | rp = (struct xpc_rsvd_page *)xpc_rsvd_page; |
89eb8eb9 DN |
421 | |
422 | /* | |
423 | * The term 'region' in this context refers to the minimum number of | |
424 | * nodes that can comprise an access protection grouping. The access | |
425 | * protection is in regards to memory, IOI and IPI. | |
426 | */ | |
4b38fcd4 DN |
427 | max_regions = 64; |
428 | region_size = sn_region_size; | |
429 | ||
430 | switch (region_size) { | |
431 | case 128: | |
432 | max_regions *= 2; | |
433 | case 64: | |
434 | max_regions *= 2; | |
435 | case 32: | |
436 | max_regions *= 2; | |
437 | region_size = 16; | |
438 | DBUG_ON(!is_shub2()); | |
439 | } | |
89eb8eb9 DN |
440 | |
441 | for (region = 0; region < max_regions; region++) { | |
442 | ||
2c2b94f9 | 443 | if (xpc_exiting) |
89eb8eb9 | 444 | break; |
89eb8eb9 DN |
445 | |
446 | dev_dbg(xpc_part, "searching region %d\n", region); | |
447 | ||
4b38fcd4 | 448 | for (nasid = (region * region_size * 2); |
4a3ad2dd | 449 | nasid < ((region + 1) * region_size * 2); nasid += 2) { |
89eb8eb9 | 450 | |
2c2b94f9 | 451 | if (xpc_exiting) |
89eb8eb9 | 452 | break; |
89eb8eb9 DN |
453 | |
454 | dev_dbg(xpc_part, "checking nasid %d\n", nasid); | |
455 | ||
4b38fcd4 | 456 | if (XPC_NASID_IN_ARRAY(nasid, xpc_part_nasids)) { |
89eb8eb9 DN |
457 | dev_dbg(xpc_part, "PROM indicates Nasid %d is " |
458 | "part of the local partition; skipping " | |
459 | "region\n", nasid); | |
460 | break; | |
461 | } | |
462 | ||
4b38fcd4 | 463 | if (!(XPC_NASID_IN_ARRAY(nasid, xpc_mach_nasids))) { |
89eb8eb9 DN |
464 | dev_dbg(xpc_part, "PROM indicates Nasid %d was " |
465 | "not on Numa-Link network at reset\n", | |
466 | nasid); | |
467 | continue; | |
468 | } | |
469 | ||
470 | if (XPC_NASID_IN_ARRAY(nasid, discovered_nasids)) { | |
471 | dev_dbg(xpc_part, "Nasid %d is part of a " | |
472 | "partition which was previously " | |
473 | "discovered\n", nasid); | |
474 | continue; | |
475 | } | |
476 | ||
33ba3c77 | 477 | /* pull over the rsvd page header & part_nasids mask */ |
89eb8eb9 DN |
478 | |
479 | ret = xpc_get_remote_rp(nasid, discovered_nasids, | |
4a3ad2dd | 480 | remote_rp, &remote_rp_pa); |
65c17b80 | 481 | if (ret != xpSuccess) { |
89eb8eb9 DN |
482 | dev_dbg(xpc_part, "unable to get reserved page " |
483 | "from nasid %d, reason=%d\n", nasid, | |
484 | ret); | |
485 | ||
65c17b80 | 486 | if (ret == xpLocalPartid) |
89eb8eb9 | 487 | break; |
2c2b94f9 | 488 | |
89eb8eb9 DN |
489 | continue; |
490 | } | |
491 | ||
a47d5dac DN |
492 | xpc_request_partition_activation(remote_rp, |
493 | remote_rp_pa, nasid); | |
89eb8eb9 DN |
494 | } |
495 | } | |
496 | ||
497 | kfree(discovered_nasids); | |
498 | kfree(remote_rp_base); | |
499 | } | |
500 | ||
89eb8eb9 DN |
501 | /* |
502 | * Given a partid, get the nasids owned by that partition from the | |
3a7d555b | 503 | * remote partition's reserved page. |
89eb8eb9 | 504 | */ |
65c17b80 | 505 | enum xp_retval |
64d032ba | 506 | xpc_initiate_partid_to_nasids(short partid, void *nasid_mask) |
89eb8eb9 DN |
507 | { |
508 | struct xpc_partition *part; | |
509 | u64 part_nasid_pa; | |
89eb8eb9 | 510 | |
89eb8eb9 | 511 | part = &xpc_partitions[partid]; |
2c2b94f9 | 512 | if (part->remote_rp_pa == 0) |
65c17b80 | 513 | return xpPartitionDown; |
89eb8eb9 | 514 | |
ee6665e3 | 515 | memset(nasid_mask, 0, xpc_sizeof_nasid_mask); |
4b38fcd4 | 516 | |
4a3ad2dd | 517 | part_nasid_pa = (u64)XPC_RP_PART_NASIDS(part->remote_rp_pa); |
89eb8eb9 | 518 | |
908787db | 519 | return xp_remote_memcpy(nasid_mask, (void *)part_nasid_pa, |
ee6665e3 | 520 | xpc_sizeof_nasid_mask); |
89eb8eb9 | 521 | } |