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 | |
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')
-rw-r--r-- | drivers/misc/sgi-xp/Makefile | 3 | ||||
-rw-r--r-- | drivers/misc/sgi-xp/xp.h | 5 | ||||
-rw-r--r-- | drivers/misc/sgi-xp/xpc.h | 57 | ||||
-rw-r--r-- | drivers/misc/sgi-xp/xpc_main.c | 27 | ||||
-rw-r--r-- | drivers/misc/sgi-xp/xpc_partition.c | 149 | ||||
-rw-r--r-- | drivers/misc/sgi-xp/xpc_sn2.c | 111 | ||||
-rw-r--r-- | drivers/misc/sgi-xp/xpc_uv.c | 48 |
7 files changed, 267 insertions, 133 deletions
diff --git a/drivers/misc/sgi-xp/Makefile b/drivers/misc/sgi-xp/Makefile index b50f29217813..b3eeff31ebf8 100644 --- a/drivers/misc/sgi-xp/Makefile +++ b/drivers/misc/sgi-xp/Makefile | |||
@@ -7,6 +7,7 @@ xp-y := xp_main.o xp_uv.o | |||
7 | xp-$(CONFIG_IA64) += xp_sn2.o xp_nofault.o | 7 | xp-$(CONFIG_IA64) += xp_sn2.o xp_nofault.o |
8 | 8 | ||
9 | obj-$(CONFIG_SGI_XP) += xpc.o | 9 | obj-$(CONFIG_SGI_XP) += xpc.o |
10 | xpc-y := xpc_main.o xpc_channel.o xpc_partition.o | 10 | xpc-y := xpc_main.o xpc_uv.o xpc_channel.o xpc_partition.o |
11 | xpc-$(CONFIG_IA64) += xpc_sn2.o | ||
11 | 12 | ||
12 | obj-$(CONFIG_SGI_XP) += xpnet.o | 13 | obj-$(CONFIG_SGI_XP) += xpnet.o |
diff --git a/drivers/misc/sgi-xp/xp.h b/drivers/misc/sgi-xp/xp.h index c42196a1a6b7..0f75592896dd 100644 --- a/drivers/misc/sgi-xp/xp.h +++ b/drivers/misc/sgi-xp/xp.h | |||
@@ -220,9 +220,10 @@ enum xp_retval { | |||
220 | 220 | ||
221 | xpBteCopyError, /* 52: bte_copy() returned error */ | 221 | xpBteCopyError, /* 52: bte_copy() returned error */ |
222 | xpSalError, /* 53: sn SAL error */ | 222 | xpSalError, /* 53: sn SAL error */ |
223 | xpRsvdPageNotSet, /* 54: the reserved page is not set up */ | ||
223 | 224 | ||
224 | xpUnsupported, /* 54: unsupported functionality or resource */ | 225 | xpUnsupported, /* 55: unsupported functionality or resource */ |
225 | xpUnknownReason /* 55: unknown reason - must be last in enum */ | 226 | xpUnknownReason /* 56: unknown reason - must be last in enum */ |
226 | }; | 227 | }; |
227 | 228 | ||
228 | /* | 229 | /* |
diff --git a/drivers/misc/sgi-xp/xpc.h b/drivers/misc/sgi-xp/xpc.h index 60388bed7701..94b52bb8151e 100644 --- a/drivers/misc/sgi-xp/xpc.h +++ b/drivers/misc/sgi-xp/xpc.h | |||
@@ -71,11 +71,11 @@ | |||
71 | * | 71 | * |
72 | * reserved page header | 72 | * reserved page header |
73 | * | 73 | * |
74 | * The first cacheline of the reserved page contains the header | 74 | * The first two 64-byte cachelines of the reserved page contain the |
75 | * (struct xpc_rsvd_page). Before SAL initialization has completed, | 75 | * header (struct xpc_rsvd_page). Before SAL initialization has completed, |
76 | * SAL has set up the following fields of the reserved page header: | 76 | * SAL has set up the following fields of the reserved page header: |
77 | * SAL_signature, SAL_version, partid, and nasids_size. The other | 77 | * SAL_signature, SAL_version, SAL_partid, and SAL_nasids_size. The |
78 | * fields are set up by XPC. (xpc_rsvd_page points to the local | 78 | * other fields are set up by XPC. (xpc_rsvd_page points to the local |
79 | * partition's reserved page.) | 79 | * partition's reserved page.) |
80 | * | 80 | * |
81 | * part_nasids mask | 81 | * part_nasids mask |
@@ -89,11 +89,11 @@ | |||
89 | * nasids. The part_nasids mask is located starting at the first cacheline | 89 | * nasids. The part_nasids mask is located starting at the first cacheline |
90 | * following the reserved page header. The mach_nasids mask follows right | 90 | * following the reserved page header. The mach_nasids mask follows right |
91 | * after the part_nasids mask. The size in bytes of each mask is reflected | 91 | * after the part_nasids mask. The size in bytes of each mask is reflected |
92 | * by the reserved page header field 'nasids_size'. (Local partition's | 92 | * by the reserved page header field 'SAL_nasids_size'. (Local partition's |
93 | * mask pointers are xpc_part_nasids and xpc_mach_nasids.) | 93 | * mask pointers are xpc_part_nasids and xpc_mach_nasids.) |
94 | * | 94 | * |
95 | * vars | 95 | * vars (ia64-sn2 only) |
96 | * vars part | 96 | * vars part (ia64-sn2 only) |
97 | * | 97 | * |
98 | * Immediately following the mach_nasids mask are the XPC variables | 98 | * Immediately following the mach_nasids mask are the XPC variables |
99 | * required by other partitions. First are those that are generic to all | 99 | * required by other partitions. First are those that are generic to all |
@@ -101,25 +101,31 @@ | |||
101 | * which are partition specific (vars part). These are setup by XPC. | 101 | * which are partition specific (vars part). These are setup by XPC. |
102 | * (Local partition's vars pointers are xpc_vars and xpc_vars_part.) | 102 | * (Local partition's vars pointers are xpc_vars and xpc_vars_part.) |
103 | * | 103 | * |
104 | * Note: Until vars_pa is set, the partition XPC code has not been initialized. | 104 | * Note: Until 'stamp' is set non-zero, the partition XPC code has not been |
105 | * initialized. | ||
105 | */ | 106 | */ |
106 | struct xpc_rsvd_page { | 107 | struct xpc_rsvd_page { |
107 | u64 SAL_signature; /* SAL: unique signature */ | 108 | u64 SAL_signature; /* SAL: unique signature */ |
108 | u64 SAL_version; /* SAL: version */ | 109 | u64 SAL_version; /* SAL: version */ |
109 | u8 partid; /* SAL: partition ID */ | 110 | short SAL_partid; /* SAL: partition ID */ |
111 | short max_npartitions; /* value of XPC_MAX_PARTITIONS */ | ||
110 | u8 version; | 112 | u8 version; |
111 | u8 pad1[6]; /* align to next u64 in cacheline */ | 113 | u8 pad1[3]; /* align to next u64 in 1st 64-byte cacheline */ |
112 | u64 vars_pa; /* physical address of struct xpc_vars */ | 114 | union { |
115 | u64 vars_pa; /* physical address of struct xpc_vars */ | ||
116 | u64 activate_mq_gpa; /* global phys address of activate_mq */ | ||
117 | } sn; | ||
113 | struct timespec stamp; /* time when reserved page was setup by XPC */ | 118 | struct timespec stamp; /* time when reserved page was setup by XPC */ |
114 | u64 pad2[9]; /* align to last u64 in cacheline */ | 119 | u64 pad2[9]; /* align to last u64 in 2nd 64-byte cacheline */ |
115 | u64 nasids_size; /* SAL: size of each nasid mask in bytes */ | 120 | u64 SAL_nasids_size; /* SAL: size of each nasid mask in bytes */ |
116 | }; | 121 | }; |
117 | 122 | ||
118 | #define XPC_RP_VERSION _XPC_VERSION(1, 1) /* version 1.1 of the reserved page */ | 123 | #define XPC_RP_VERSION _XPC_VERSION(2, 0) /* version 2.0 of the reserved page */ |
119 | 124 | ||
120 | #define XPC_SUPPORTS_RP_STAMP(_version) \ | 125 | #define XPC_SUPPORTS_RP_STAMP(_version) \ |
121 | (_version >= _XPC_VERSION(1, 1)) | 126 | (_version >= _XPC_VERSION(1, 1)) |
122 | 127 | ||
128 | #define ZERO_STAMP ((struct timespec){0, 0}) | ||
123 | /* | 129 | /* |
124 | * compare stamps - the return value is: | 130 | * compare stamps - the return value is: |
125 | * | 131 | * |
@@ -218,10 +224,10 @@ xpc_disallow_hb(short partid, struct xpc_vars *vars) | |||
218 | * | 224 | * |
219 | * An array of these structures, one per partition, will be defined. As a | 225 | * An array of these structures, one per partition, will be defined. As a |
220 | * partition becomes active XPC will copy the array entry corresponding to | 226 | * partition becomes active XPC will copy the array entry corresponding to |
221 | * itself from that partition. It is desirable that the size of this | 227 | * itself from that partition. It is desirable that the size of this structure |
222 | * structure evenly divide into a cacheline, such that none of the entries | 228 | * evenly divides into a 128-byte cacheline, such that none of the entries in |
223 | * in this array crosses a cacheline boundary. As it is now, each entry | 229 | * this array crosses a 128-byte cacheline boundary. As it is now, each entry |
224 | * occupies half a cacheline. | 230 | * occupies a 64-byte cacheline. |
225 | */ | 231 | */ |
226 | struct xpc_vars_part { | 232 | struct xpc_vars_part { |
227 | u64 magic; | 233 | u64 magic; |
@@ -632,16 +638,25 @@ extern void xpc_activate_kthreads(struct xpc_channel *, int); | |||
632 | extern void xpc_create_kthreads(struct xpc_channel *, int, int); | 638 | extern void xpc_create_kthreads(struct xpc_channel *, int, int); |
633 | extern void xpc_disconnect_wait(int); | 639 | extern void xpc_disconnect_wait(int); |
634 | 640 | ||
641 | extern enum xp_retval (*xpc_rsvd_page_init) (struct xpc_rsvd_page *); | ||
642 | |||
643 | /* found in xpc_sn2.c */ | ||
644 | extern void xpc_init_sn2(void); | ||
645 | extern struct xpc_vars *xpc_vars; /*>>> eliminate from here */ | ||
646 | extern struct xpc_vars_part *xpc_vars_part; /*>>> eliminate from here */ | ||
647 | |||
648 | /* found in xpc_uv.c */ | ||
649 | extern void xpc_init_uv(void); | ||
650 | |||
635 | /* found in xpc_partition.c */ | 651 | /* found in xpc_partition.c */ |
636 | extern int xpc_exiting; | 652 | extern int xpc_exiting; |
637 | extern struct xpc_vars *xpc_vars; | 653 | extern int xp_nasid_mask_words; |
638 | extern struct xpc_rsvd_page *xpc_rsvd_page; | 654 | extern struct xpc_rsvd_page *xpc_rsvd_page; |
639 | extern struct xpc_vars_part *xpc_vars_part; | ||
640 | extern struct xpc_partition *xpc_partitions; | 655 | extern struct xpc_partition *xpc_partitions; |
641 | extern char *xpc_remote_copy_buffer; | 656 | extern char *xpc_remote_copy_buffer; |
642 | extern void *xpc_remote_copy_buffer_base; | 657 | extern void *xpc_remote_copy_buffer_base; |
643 | extern void *xpc_kmalloc_cacheline_aligned(size_t, gfp_t, void **); | 658 | extern void *xpc_kmalloc_cacheline_aligned(size_t, gfp_t, void **); |
644 | extern struct xpc_rsvd_page *xpc_rsvd_page_init(void); | 659 | extern struct xpc_rsvd_page *xpc_setup_rsvd_page(void); |
645 | extern void xpc_allow_IPI_ops(void); | 660 | extern void xpc_allow_IPI_ops(void); |
646 | extern void xpc_restrict_IPI_ops(void); | 661 | extern void xpc_restrict_IPI_ops(void); |
647 | extern int xpc_identify_act_IRQ_sender(void); | 662 | extern int xpc_identify_act_IRQ_sender(void); |
diff --git a/drivers/misc/sgi-xp/xpc_main.c b/drivers/misc/sgi-xp/xpc_main.c index a05c7c7da228..2180f1f7e087 100644 --- a/drivers/misc/sgi-xp/xpc_main.c +++ b/drivers/misc/sgi-xp/xpc_main.c | |||
@@ -175,6 +175,8 @@ static struct notifier_block xpc_die_notifier = { | |||
175 | .notifier_call = xpc_system_die, | 175 | .notifier_call = xpc_system_die, |
176 | }; | 176 | }; |
177 | 177 | ||
178 | enum xp_retval (*xpc_rsvd_page_init) (struct xpc_rsvd_page *rp); | ||
179 | |||
178 | /* | 180 | /* |
179 | * Timer function to enforce the timelimit on the partition disengage request. | 181 | * Timer function to enforce the timelimit on the partition disengage request. |
180 | */ | 182 | */ |
@@ -949,7 +951,7 @@ xpc_do_exit(enum xp_retval reason) | |||
949 | DBUG_ON(xpc_partition_engaged(-1UL)); | 951 | DBUG_ON(xpc_partition_engaged(-1UL)); |
950 | 952 | ||
951 | /* indicate to others that our reserved page is uninitialized */ | 953 | /* indicate to others that our reserved page is uninitialized */ |
952 | xpc_rsvd_page->vars_pa = 0; | 954 | xpc_rsvd_page->stamp = ZERO_STAMP; |
953 | 955 | ||
954 | /* now it's time to eliminate our heartbeat */ | 956 | /* now it's time to eliminate our heartbeat */ |
955 | del_timer_sync(&xpc_hb_timer); | 957 | del_timer_sync(&xpc_hb_timer); |
@@ -1128,8 +1130,24 @@ xpc_init(void) | |||
1128 | struct task_struct *kthread; | 1130 | struct task_struct *kthread; |
1129 | size_t buf_size; | 1131 | size_t buf_size; |
1130 | 1132 | ||
1131 | if (!ia64_platform_is("sn2")) | 1133 | if (is_shub()) { |
1134 | /* | ||
1135 | * The ia64-sn2 architecture supports at most 64 partitions. | ||
1136 | * And the inability to unregister remote AMOs restricts us | ||
1137 | * further to only support exactly 64 partitions on this | ||
1138 | * architecture, no less. | ||
1139 | */ | ||
1140 | if (xp_max_npartitions != 64) | ||
1141 | return -EINVAL; | ||
1142 | |||
1143 | xpc_init_sn2(); | ||
1144 | |||
1145 | } else if (is_uv()) { | ||
1146 | xpc_init_uv(); | ||
1147 | |||
1148 | } else { | ||
1132 | return -ENODEV; | 1149 | return -ENODEV; |
1150 | } | ||
1133 | 1151 | ||
1134 | snprintf(xpc_part->bus_id, BUS_ID_SIZE, "part"); | 1152 | snprintf(xpc_part->bus_id, BUS_ID_SIZE, "part"); |
1135 | snprintf(xpc_chan->bus_id, BUS_ID_SIZE, "chan"); | 1153 | snprintf(xpc_chan->bus_id, BUS_ID_SIZE, "chan"); |
@@ -1214,7 +1232,7 @@ xpc_init(void) | |||
1214 | * other partitions to discover we are alive and establish initial | 1232 | * other partitions to discover we are alive and establish initial |
1215 | * communications. | 1233 | * communications. |
1216 | */ | 1234 | */ |
1217 | xpc_rsvd_page = xpc_rsvd_page_init(); | 1235 | xpc_rsvd_page = xpc_setup_rsvd_page(); |
1218 | if (xpc_rsvd_page == NULL) { | 1236 | if (xpc_rsvd_page == NULL) { |
1219 | dev_err(xpc_part, "can't setup our reserved page\n"); | 1237 | dev_err(xpc_part, "can't setup our reserved page\n"); |
1220 | ret = -EBUSY; | 1238 | ret = -EBUSY; |
@@ -1273,7 +1291,8 @@ xpc_init(void) | |||
1273 | /* initialization was not successful */ | 1291 | /* initialization was not successful */ |
1274 | out_4: | 1292 | out_4: |
1275 | /* indicate to others that our reserved page is uninitialized */ | 1293 | /* indicate to others that our reserved page is uninitialized */ |
1276 | xpc_rsvd_page->vars_pa = 0; | 1294 | xpc_rsvd_page->stamp = ZERO_STAMP; |
1295 | |||
1277 | del_timer_sync(&xpc_hb_timer); | 1296 | del_timer_sync(&xpc_hb_timer); |
1278 | (void)unregister_die_notifier(&xpc_die_notifier); | 1297 | (void)unregister_die_notifier(&xpc_die_notifier); |
1279 | (void)unregister_reboot_notifier(&xpc_reboot_notifier); | 1298 | (void)unregister_reboot_notifier(&xpc_reboot_notifier); |
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 | } |
diff --git a/drivers/misc/sgi-xp/xpc_sn2.c b/drivers/misc/sgi-xp/xpc_sn2.c new file mode 100644 index 000000000000..5a37348715c7 --- /dev/null +++ b/drivers/misc/sgi-xp/xpc_sn2.c | |||
@@ -0,0 +1,111 @@ | |||
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 | } | ||
diff --git a/drivers/misc/sgi-xp/xpc_uv.c b/drivers/misc/sgi-xp/xpc_uv.c new file mode 100644 index 000000000000..8327cd4017ec --- /dev/null +++ b/drivers/misc/sgi-xp/xpc_uv.c | |||
@@ -0,0 +1,48 @@ | |||
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) uv-based functions. | ||
11 | * | ||
12 | * Architecture specific implementation of common functions. | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #include <linux/kernel.h> | ||
17 | |||
18 | /* >>> #include <gru/grukservices.h> */ | ||
19 | /* >>> uv_gpa() is defined in <gru/grukservices.h> */ | ||
20 | #define uv_gpa(_a) ((unsigned long)_a) | ||
21 | |||
22 | /* >>> temporarily define next three items for xpc.h */ | ||
23 | #define SGI_XPC_ACTIVATE 23 | ||
24 | #define SGI_XPC_NOTIFY 24 | ||
25 | #define sn_send_IPI_phys(_a, _b, _c, _d) | ||
26 | |||
27 | #include "xpc.h" | ||
28 | |||
29 | static void *xpc_activate_mq; | ||
30 | |||
31 | static enum xp_retval | ||
32 | xpc_rsvd_page_init_uv(struct xpc_rsvd_page *rp) | ||
33 | { | ||
34 | /* >>> need to have established xpc_activate_mq earlier */ | ||
35 | rp->sn.activate_mq_gpa = uv_gpa(xpc_activate_mq); | ||
36 | return xpSuccess; | ||
37 | } | ||
38 | |||
39 | void | ||
40 | xpc_init_uv(void) | ||
41 | { | ||
42 | xpc_rsvd_page_init = xpc_rsvd_page_init_uv; | ||
43 | } | ||
44 | |||
45 | void | ||
46 | xpc_exit_uv(void) | ||
47 | { | ||
48 | } | ||