diff options
author | Jack Steiner <steiner@sgi.com> | 2006-05-31 09:58:08 -0400 |
---|---|---|
committer | Tony Luck <tony.luck@intel.com> | 2006-06-21 17:33:56 -0400 |
commit | a1d7057727bc9e20a0a417812f538fe6b8a02c03 (patch) | |
tree | bd3627eb3ea4b916dd1de521c341b92e3444f4dd /arch/ia64 | |
parent | 5eb1d63f5fc8455269c2756223b3cf3779fd2f7a (diff) |
[IA64-SGI] SN topology fix for large systems
There is an SN bug in sn_hwperf.c that affects systems with 1024n or 1024p.
The bug manifests itself 2 ways: IO interrupts are not always
targeted to the nearest node, and 2) the "cat /proc/sgi_sn/sn_topology"
commands fails with "cannot allocate memory".
The code is using the wrong macros for validating node numbers.
Signed-off-by: Jack Steiner <steiner@sgi.com>
Signed-off-by: Tony Luck <tony.luck@intel.com>
Diffstat (limited to 'arch/ia64')
-rw-r--r-- | arch/ia64/sn/kernel/sn2/sn_hwperf.c | 50 |
1 files changed, 27 insertions, 23 deletions
diff --git a/arch/ia64/sn/kernel/sn2/sn_hwperf.c b/arch/ia64/sn/kernel/sn2/sn_hwperf.c index 739c948dc504..9a8a29339d2d 100644 --- a/arch/ia64/sn/kernel/sn2/sn_hwperf.c +++ b/arch/ia64/sn/kernel/sn2/sn_hwperf.c | |||
@@ -51,6 +51,8 @@ static nasid_t sn_hwperf_master_nasid = INVALID_NASID; | |||
51 | static int sn_hwperf_init(void); | 51 | static int sn_hwperf_init(void); |
52 | static DECLARE_MUTEX(sn_hwperf_init_mutex); | 52 | static DECLARE_MUTEX(sn_hwperf_init_mutex); |
53 | 53 | ||
54 | #define cnode_possible(n) ((n) < num_cnodes) | ||
55 | |||
54 | static int sn_hwperf_enum_objects(int *nobj, struct sn_hwperf_object_info **ret) | 56 | static int sn_hwperf_enum_objects(int *nobj, struct sn_hwperf_object_info **ret) |
55 | { | 57 | { |
56 | int e; | 58 | int e; |
@@ -127,14 +129,14 @@ static int sn_hwperf_geoid_to_cnode(char *location) | |||
127 | } | 129 | } |
128 | } | 130 | } |
129 | 131 | ||
130 | return node_possible(cnode) ? cnode : -1; | 132 | return cnode_possible(cnode) ? cnode : -1; |
131 | } | 133 | } |
132 | 134 | ||
133 | static int sn_hwperf_obj_to_cnode(struct sn_hwperf_object_info * obj) | 135 | static int sn_hwperf_obj_to_cnode(struct sn_hwperf_object_info * obj) |
134 | { | 136 | { |
135 | if (!SN_HWPERF_IS_NODE(obj) && !SN_HWPERF_IS_IONODE(obj)) | 137 | if (!SN_HWPERF_IS_NODE(obj) && !SN_HWPERF_IS_IONODE(obj)) |
136 | BUG(); | 138 | BUG(); |
137 | if (!obj->sn_hwp_this_part) | 139 | if (SN_HWPERF_FOREIGN(obj)) |
138 | return -1; | 140 | return -1; |
139 | return sn_hwperf_geoid_to_cnode(obj->location); | 141 | return sn_hwperf_geoid_to_cnode(obj->location); |
140 | } | 142 | } |
@@ -199,12 +201,12 @@ static void print_pci_topology(struct seq_file *s) | |||
199 | 201 | ||
200 | static inline int sn_hwperf_has_cpus(cnodeid_t node) | 202 | static inline int sn_hwperf_has_cpus(cnodeid_t node) |
201 | { | 203 | { |
202 | return node_online(node) && nr_cpus_node(node); | 204 | return node < MAX_NUMNODES && node_online(node) && nr_cpus_node(node); |
203 | } | 205 | } |
204 | 206 | ||
205 | static inline int sn_hwperf_has_mem(cnodeid_t node) | 207 | static inline int sn_hwperf_has_mem(cnodeid_t node) |
206 | { | 208 | { |
207 | return node_online(node) && NODE_DATA(node)->node_present_pages; | 209 | return node < MAX_NUMNODES && node_online(node) && NODE_DATA(node)->node_present_pages; |
208 | } | 210 | } |
209 | 211 | ||
210 | static struct sn_hwperf_object_info * | 212 | static struct sn_hwperf_object_info * |
@@ -237,7 +239,7 @@ static int sn_hwperf_get_nearest_node_objdata(struct sn_hwperf_object_info *objb | |||
237 | int found_mem = 0; | 239 | int found_mem = 0; |
238 | int found_cpu = 0; | 240 | int found_cpu = 0; |
239 | 241 | ||
240 | if (!node_possible(node)) | 242 | if (!cnode_possible(node)) |
241 | return -EINVAL; | 243 | return -EINVAL; |
242 | 244 | ||
243 | if (sn_hwperf_has_cpus(node)) { | 245 | if (sn_hwperf_has_cpus(node)) { |
@@ -442,7 +444,7 @@ static int sn_topology_show(struct seq_file *s, void *d) | |||
442 | seq_printf(s, "%s %d %s %s asic %s", slabname, ordinal, obj->location, | 444 | seq_printf(s, "%s %d %s %s asic %s", slabname, ordinal, obj->location, |
443 | obj->sn_hwp_this_part ? "local" : "shared", obj->name); | 445 | obj->sn_hwp_this_part ? "local" : "shared", obj->name); |
444 | 446 | ||
445 | if (!SN_HWPERF_IS_NODE(obj) && !SN_HWPERF_IS_IONODE(obj)) | 447 | if (ordinal < 0 || (!SN_HWPERF_IS_NODE(obj) && !SN_HWPERF_IS_IONODE(obj))) |
446 | seq_putc(s, '\n'); | 448 | seq_putc(s, '\n'); |
447 | else { | 449 | else { |
448 | cnodeid_t near_mem = -1; | 450 | cnodeid_t near_mem = -1; |
@@ -468,22 +470,24 @@ static int sn_topology_show(struct seq_file *s, void *d) | |||
468 | /* | 470 | /* |
469 | * CPUs on this node, if any | 471 | * CPUs on this node, if any |
470 | */ | 472 | */ |
471 | cpumask = node_to_cpumask(ordinal); | 473 | if (!SN_HWPERF_IS_IONODE(obj)) { |
472 | for_each_online_cpu(i) { | 474 | cpumask = node_to_cpumask(ordinal); |
473 | if (cpu_isset(i, cpumask)) { | 475 | for_each_online_cpu(i) { |
474 | slice = 'a' + cpuid_to_slice(i); | 476 | if (cpu_isset(i, cpumask)) { |
475 | c = cpu_data(i); | 477 | slice = 'a' + cpuid_to_slice(i); |
476 | seq_printf(s, "cpu %d %s%c local" | 478 | c = cpu_data(i); |
477 | " freq %luMHz, arch ia64", | 479 | seq_printf(s, "cpu %d %s%c local" |
478 | i, obj->location, slice, | 480 | " freq %luMHz, arch ia64", |
479 | c->proc_freq / 1000000); | 481 | i, obj->location, slice, |
480 | for_each_online_cpu(j) { | 482 | c->proc_freq / 1000000); |
481 | seq_printf(s, j ? ":%d" : ", dist %d", | 483 | for_each_online_cpu(j) { |
482 | node_distance( | 484 | seq_printf(s, j ? ":%d" : ", dist %d", |
483 | cpu_to_node(i), | 485 | node_distance( |
484 | cpu_to_node(j))); | 486 | cpu_to_node(i), |
487 | cpu_to_node(j))); | ||
488 | } | ||
489 | seq_putc(s, '\n'); | ||
485 | } | 490 | } |
486 | seq_putc(s, '\n'); | ||
487 | } | 491 | } |
488 | } | 492 | } |
489 | } | 493 | } |
@@ -523,7 +527,7 @@ static int sn_topology_show(struct seq_file *s, void *d) | |||
523 | if (obj->sn_hwp_this_part && p->sn_hwp_this_part) | 527 | if (obj->sn_hwp_this_part && p->sn_hwp_this_part) |
524 | /* both ends local to this partition */ | 528 | /* both ends local to this partition */ |
525 | seq_puts(s, " local"); | 529 | seq_puts(s, " local"); |
526 | else if (!obj->sn_hwp_this_part && !p->sn_hwp_this_part) | 530 | else if (SN_HWPERF_FOREIGN(p)) |
527 | /* both ends of the link in foreign partiton */ | 531 | /* both ends of the link in foreign partiton */ |
528 | seq_puts(s, " foreign"); | 532 | seq_puts(s, " foreign"); |
529 | else | 533 | else |
@@ -776,7 +780,7 @@ sn_hwperf_ioctl(struct inode *in, struct file *fp, u32 op, u64 arg) | |||
776 | 780 | ||
777 | case SN_HWPERF_GET_NODE_NASID: | 781 | case SN_HWPERF_GET_NODE_NASID: |
778 | if (a.sz != sizeof(u64) || | 782 | if (a.sz != sizeof(u64) || |
779 | (node = a.arg) < 0 || !node_possible(node)) { | 783 | (node = a.arg) < 0 || !cnode_possible(node)) { |
780 | r = -EINVAL; | 784 | r = -EINVAL; |
781 | goto error; | 785 | goto error; |
782 | } | 786 | } |