5a37348715c7b5b0a424335c2d80bee65ed2fb9c
[pandora-kernel.git] / drivers / misc / sgi-xp / xpc_sn2.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) 2008 Silicon Graphics, Inc.  All Rights Reserved.
7  */
8
9 /*
10  * Cross Partition Communication (XPC) sn2-based functions.
11  *
12  *     Architecture specific implementation of common functions.
13  *
14  */
15
16 #include <linux/kernel.h>
17 #include <asm/uncached.h>
18 #include <asm/sn/sn_sal.h>
19 #include "xpc.h"
20
21 struct xpc_vars *xpc_vars;
22 struct xpc_vars_part *xpc_vars_part;
23
24 static enum xp_retval
25 xpc_rsvd_page_init_sn2(struct xpc_rsvd_page *rp)
26 {
27         AMO_t *amos_page;
28         u64 nasid_array = 0;
29         int i;
30         int ret;
31
32         xpc_vars = XPC_RP_VARS(rp);
33
34         rp->sn.vars_pa = __pa(xpc_vars);
35
36         xpc_vars_part = XPC_RP_VARS_PART(rp);
37
38         /*
39          * Before clearing xpc_vars, see if a page of AMOs had been previously
40          * allocated. If not we'll need to allocate one and set permissions
41          * so that cross-partition AMOs are allowed.
42          *
43          * The allocated AMO page needs MCA reporting to remain disabled after
44          * XPC has unloaded.  To make this work, we keep a copy of the pointer
45          * to this page (i.e., amos_page) in the struct xpc_vars structure,
46          * which is pointed to by the reserved page, and re-use that saved copy
47          * on subsequent loads of XPC. This AMO page is never freed, and its
48          * memory protections are never restricted.
49          */
50         amos_page = xpc_vars->amos_page;
51         if (amos_page == NULL) {
52                 amos_page = (AMO_t *)TO_AMO(uncached_alloc_page(0, 1));
53                 if (amos_page == NULL) {
54                         dev_err(xpc_part, "can't allocate page of AMOs\n");
55                         return xpNoMemory;
56                 }
57
58                 /*
59                  * Open up AMO-R/W to cpu.  This is done for Shub 1.1 systems
60                  * when xpc_allow_IPI_ops() is called via xpc_hb_init().
61                  */
62                 if (!enable_shub_wars_1_1()) {
63                         ret = sn_change_memprotect(ia64_tpa((u64)amos_page),
64                                                    PAGE_SIZE,
65                                                    SN_MEMPROT_ACCESS_CLASS_1,
66                                                    &nasid_array);
67                         if (ret != 0) {
68                                 dev_err(xpc_part, "can't change memory "
69                                         "protections\n");
70                                 uncached_free_page(__IA64_UNCACHED_OFFSET |
71                                                    TO_PHYS((u64)amos_page), 1);
72                                 return xpSalError;
73                         }
74                 }
75         }
76
77         /* clear xpc_vars */
78         memset(xpc_vars, 0, sizeof(struct xpc_vars));
79
80         xpc_vars->version = XPC_V_VERSION;
81         xpc_vars->act_nasid = cpuid_to_nasid(0);
82         xpc_vars->act_phys_cpuid = cpu_physical_id(0);
83         xpc_vars->vars_part_pa = __pa(xpc_vars_part);
84         xpc_vars->amos_page_pa = ia64_tpa((u64)amos_page);
85         xpc_vars->amos_page = amos_page;        /* save for next load of XPC */
86
87         /* clear xpc_vars_part */
88         memset((u64 *)xpc_vars_part, 0, sizeof(struct xpc_vars_part) *
89                xp_max_npartitions);
90
91         /* initialize the activate IRQ related AMO variables */
92         for (i = 0; i < xp_nasid_mask_words; i++)
93                 (void)xpc_IPI_init(XPC_ACTIVATE_IRQ_AMOS + i);
94
95         /* initialize the engaged remote partitions related AMO variables */
96         (void)xpc_IPI_init(XPC_ENGAGED_PARTITIONS_AMO);
97         (void)xpc_IPI_init(XPC_DISENGAGE_REQUEST_AMO);
98
99         return xpSuccess;
100 }
101
102 void
103 xpc_init_sn2(void)
104 {
105         xpc_rsvd_page_init = xpc_rsvd_page_init_sn2;
106 }
107
108 void
109 xpc_exit_sn2(void)
110 {
111 }