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