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