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 | |
| 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>
| -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 | } | ||
