diff options
author | Jeff Garzik <jgarzik@pobox.com> | 2005-09-08 05:39:55 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2005-09-08 05:39:55 -0400 |
commit | c324b44c34050cf2a9b58830e11c974806bd85d8 (patch) | |
tree | 3ac45a783221283925cd698334a8f5e7dd4c1df8 /arch/ia64/sn/kernel/sn2 | |
parent | 2fcf522509cceea524b6e7ece8fd6759b682175a (diff) | |
parent | caf39e87cc1182f7dae84eefc43ca14d54c78ef9 (diff) |
Merge /spare/repo/linux-2.6/
Diffstat (limited to 'arch/ia64/sn/kernel/sn2')
-rw-r--r-- | arch/ia64/sn/kernel/sn2/ptc_deadlock.S | 13 | ||||
-rw-r--r-- | arch/ia64/sn/kernel/sn2/sn2_smp.c | 256 | ||||
-rw-r--r-- | arch/ia64/sn/kernel/sn2/sn_hwperf.c | 313 | ||||
-rw-r--r-- | arch/ia64/sn/kernel/sn2/sn_proc_fs.c | 4 | ||||
-rw-r--r-- | arch/ia64/sn/kernel/sn2/timer_interrupt.c | 22 |
5 files changed, 516 insertions, 92 deletions
diff --git a/arch/ia64/sn/kernel/sn2/ptc_deadlock.S b/arch/ia64/sn/kernel/sn2/ptc_deadlock.S index 96cb71d15682..3fa95065a446 100644 --- a/arch/ia64/sn/kernel/sn2/ptc_deadlock.S +++ b/arch/ia64/sn/kernel/sn2/ptc_deadlock.S | |||
@@ -3,7 +3,7 @@ | |||
3 | * License. See the file "COPYING" in the main directory of this archive | 3 | * License. See the file "COPYING" in the main directory of this archive |
4 | * for more details. | 4 | * for more details. |
5 | * | 5 | * |
6 | * Copyright (C) 2000-2004 Silicon Graphics, Inc. All rights reserved. | 6 | * Copyright (C) 2000-2005 Silicon Graphics, Inc. All rights reserved. |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <asm/types.h> | 9 | #include <asm/types.h> |
@@ -11,7 +11,7 @@ | |||
11 | 11 | ||
12 | #define DEADLOCKBIT SH_PIO_WRITE_STATUS_WRITE_DEADLOCK_SHFT | 12 | #define DEADLOCKBIT SH_PIO_WRITE_STATUS_WRITE_DEADLOCK_SHFT |
13 | #define WRITECOUNTMASK SH_PIO_WRITE_STATUS_PENDING_WRITE_COUNT_MASK | 13 | #define WRITECOUNTMASK SH_PIO_WRITE_STATUS_PENDING_WRITE_COUNT_MASK |
14 | #define ALIAS_OFFSET (SH1_PIO_WRITE_STATUS_0_ALIAS-SH1_PIO_WRITE_STATUS_0) | 14 | #define ALIAS_OFFSET 8 |
15 | 15 | ||
16 | 16 | ||
17 | .global sn2_ptc_deadlock_recovery_core | 17 | .global sn2_ptc_deadlock_recovery_core |
@@ -36,13 +36,15 @@ sn2_ptc_deadlock_recovery_core: | |||
36 | extr.u piowcphy=piowc,0,61;; // Convert piowc to uncached physical address | 36 | extr.u piowcphy=piowc,0,61;; // Convert piowc to uncached physical address |
37 | dep piowcphy=-1,piowcphy,63,1 | 37 | dep piowcphy=-1,piowcphy,63,1 |
38 | movl mask=WRITECOUNTMASK | 38 | movl mask=WRITECOUNTMASK |
39 | mov r8=r0 | ||
39 | 40 | ||
40 | 1: | 41 | 1: |
41 | add scr2=ALIAS_OFFSET,piowc // Address of WRITE_STATUS alias register | 42 | add scr2=ALIAS_OFFSET,piowc // Address of WRITE_STATUS alias register |
42 | mov scr1=7;; // Clear DEADLOCK, WRITE_ERROR, MULTI_WRITE_ERROR | 43 | ;; |
43 | st8.rel [scr2]=scr1;; | 44 | ld8.acq scr1=[scr2];; |
44 | 45 | ||
45 | 5: ld8.acq scr1=[piowc];; // Wait for PIOs to complete. | 46 | 5: ld8.acq scr1=[piowc];; // Wait for PIOs to complete. |
47 | hint @pause | ||
46 | and scr2=scr1,mask;; // mask of writecount bits | 48 | and scr2=scr1,mask;; // mask of writecount bits |
47 | cmp.ne p6,p0=zeroval,scr2 | 49 | cmp.ne p6,p0=zeroval,scr2 |
48 | (p6) br.cond.sptk 5b | 50 | (p6) br.cond.sptk 5b |
@@ -57,6 +59,7 @@ sn2_ptc_deadlock_recovery_core: | |||
57 | st8.rel [ptc0]=data0 // Write PTC0 & wait for completion. | 59 | st8.rel [ptc0]=data0 // Write PTC0 & wait for completion. |
58 | 60 | ||
59 | 5: ld8.acq scr1=[piowcphy];; // Wait for PIOs to complete. | 61 | 5: ld8.acq scr1=[piowcphy];; // Wait for PIOs to complete. |
62 | hint @pause | ||
60 | and scr2=scr1,mask;; // mask of writecount bits | 63 | and scr2=scr1,mask;; // mask of writecount bits |
61 | cmp.ne p6,p0=zeroval,scr2 | 64 | cmp.ne p6,p0=zeroval,scr2 |
62 | (p6) br.cond.sptk 5b;; | 65 | (p6) br.cond.sptk 5b;; |
@@ -67,6 +70,7 @@ sn2_ptc_deadlock_recovery_core: | |||
67 | (p7) st8.rel [ptc1]=data1;; // Now write PTC1. | 70 | (p7) st8.rel [ptc1]=data1;; // Now write PTC1. |
68 | 71 | ||
69 | 5: ld8.acq scr1=[piowcphy];; // Wait for PIOs to complete. | 72 | 5: ld8.acq scr1=[piowcphy];; // Wait for PIOs to complete. |
73 | hint @pause | ||
70 | and scr2=scr1,mask;; // mask of writecount bits | 74 | and scr2=scr1,mask;; // mask of writecount bits |
71 | cmp.ne p6,p0=zeroval,scr2 | 75 | cmp.ne p6,p0=zeroval,scr2 |
72 | (p6) br.cond.sptk 5b | 76 | (p6) br.cond.sptk 5b |
@@ -77,6 +81,7 @@ sn2_ptc_deadlock_recovery_core: | |||
77 | srlz.i;; | 81 | srlz.i;; |
78 | ////////////// END PHYSICAL MODE //////////////////// | 82 | ////////////// END PHYSICAL MODE //////////////////// |
79 | 83 | ||
84 | (p8) add r8=1,r8 | ||
80 | (p8) br.cond.spnt 1b;; // Repeat if DEADLOCK occurred. | 85 | (p8) br.cond.spnt 1b;; // Repeat if DEADLOCK occurred. |
81 | 86 | ||
82 | br.ret.sptk rp | 87 | br.ret.sptk rp |
diff --git a/arch/ia64/sn/kernel/sn2/sn2_smp.c b/arch/ia64/sn/kernel/sn2/sn2_smp.c index 7af05a7ac743..0a4ee50c302f 100644 --- a/arch/ia64/sn/kernel/sn2/sn2_smp.c +++ b/arch/ia64/sn/kernel/sn2/sn2_smp.c | |||
@@ -5,7 +5,7 @@ | |||
5 | * License. See the file "COPYING" in the main directory of this archive | 5 | * License. See the file "COPYING" in the main directory of this archive |
6 | * for more details. | 6 | * for more details. |
7 | * | 7 | * |
8 | * Copyright (C) 2000-2004 Silicon Graphics, Inc. All rights reserved. | 8 | * Copyright (C) 2000-2005 Silicon Graphics, Inc. All rights reserved. |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/init.h> | 11 | #include <linux/init.h> |
@@ -20,6 +20,8 @@ | |||
20 | #include <linux/module.h> | 20 | #include <linux/module.h> |
21 | #include <linux/bitops.h> | 21 | #include <linux/bitops.h> |
22 | #include <linux/nodemask.h> | 22 | #include <linux/nodemask.h> |
23 | #include <linux/proc_fs.h> | ||
24 | #include <linux/seq_file.h> | ||
23 | 25 | ||
24 | #include <asm/processor.h> | 26 | #include <asm/processor.h> |
25 | #include <asm/irq.h> | 27 | #include <asm/irq.h> |
@@ -39,12 +41,120 @@ | |||
39 | #include <asm/sn/nodepda.h> | 41 | #include <asm/sn/nodepda.h> |
40 | #include <asm/sn/rw_mmr.h> | 42 | #include <asm/sn/rw_mmr.h> |
41 | 43 | ||
42 | void sn2_ptc_deadlock_recovery(volatile unsigned long *, unsigned long data0, | 44 | DEFINE_PER_CPU(struct ptc_stats, ptcstats); |
43 | volatile unsigned long *, unsigned long data1); | 45 | DECLARE_PER_CPU(struct ptc_stats, ptcstats); |
44 | 46 | ||
45 | static __cacheline_aligned DEFINE_SPINLOCK(sn2_global_ptc_lock); | 47 | static __cacheline_aligned DEFINE_SPINLOCK(sn2_global_ptc_lock); |
46 | 48 | ||
47 | static unsigned long sn2_ptc_deadlock_count; | 49 | void sn2_ptc_deadlock_recovery(short *, short, int, volatile unsigned long *, unsigned long data0, |
50 | volatile unsigned long *, unsigned long data1); | ||
51 | |||
52 | #ifdef DEBUG_PTC | ||
53 | /* | ||
54 | * ptctest: | ||
55 | * | ||
56 | * xyz - 3 digit hex number: | ||
57 | * x - Force PTC purges to use shub: | ||
58 | * 0 - no force | ||
59 | * 1 - force | ||
60 | * y - interupt enable | ||
61 | * 0 - disable interrupts | ||
62 | * 1 - leave interuupts enabled | ||
63 | * z - type of lock: | ||
64 | * 0 - global lock | ||
65 | * 1 - node local lock | ||
66 | * 2 - no lock | ||
67 | * | ||
68 | * Note: on shub1, only ptctest == 0 is supported. Don't try other values! | ||
69 | */ | ||
70 | |||
71 | static unsigned int sn2_ptctest = 0; | ||
72 | |||
73 | static int __init ptc_test(char *str) | ||
74 | { | ||
75 | get_option(&str, &sn2_ptctest); | ||
76 | return 1; | ||
77 | } | ||
78 | __setup("ptctest=", ptc_test); | ||
79 | |||
80 | static inline int ptc_lock(unsigned long *flagp) | ||
81 | { | ||
82 | unsigned long opt = sn2_ptctest & 255; | ||
83 | |||
84 | switch (opt) { | ||
85 | case 0x00: | ||
86 | spin_lock_irqsave(&sn2_global_ptc_lock, *flagp); | ||
87 | break; | ||
88 | case 0x01: | ||
89 | spin_lock_irqsave(&sn_nodepda->ptc_lock, *flagp); | ||
90 | break; | ||
91 | case 0x02: | ||
92 | local_irq_save(*flagp); | ||
93 | break; | ||
94 | case 0x10: | ||
95 | spin_lock(&sn2_global_ptc_lock); | ||
96 | break; | ||
97 | case 0x11: | ||
98 | spin_lock(&sn_nodepda->ptc_lock); | ||
99 | break; | ||
100 | case 0x12: | ||
101 | break; | ||
102 | default: | ||
103 | BUG(); | ||
104 | } | ||
105 | return opt; | ||
106 | } | ||
107 | |||
108 | static inline void ptc_unlock(unsigned long flags, int opt) | ||
109 | { | ||
110 | switch (opt) { | ||
111 | case 0x00: | ||
112 | spin_unlock_irqrestore(&sn2_global_ptc_lock, flags); | ||
113 | break; | ||
114 | case 0x01: | ||
115 | spin_unlock_irqrestore(&sn_nodepda->ptc_lock, flags); | ||
116 | break; | ||
117 | case 0x02: | ||
118 | local_irq_restore(flags); | ||
119 | break; | ||
120 | case 0x10: | ||
121 | spin_unlock(&sn2_global_ptc_lock); | ||
122 | break; | ||
123 | case 0x11: | ||
124 | spin_unlock(&sn_nodepda->ptc_lock); | ||
125 | break; | ||
126 | case 0x12: | ||
127 | break; | ||
128 | default: | ||
129 | BUG(); | ||
130 | } | ||
131 | } | ||
132 | #else | ||
133 | |||
134 | #define sn2_ptctest 0 | ||
135 | |||
136 | static inline int ptc_lock(unsigned long *flagp) | ||
137 | { | ||
138 | spin_lock_irqsave(&sn2_global_ptc_lock, *flagp); | ||
139 | return 0; | ||
140 | } | ||
141 | |||
142 | static inline void ptc_unlock(unsigned long flags, int opt) | ||
143 | { | ||
144 | spin_unlock_irqrestore(&sn2_global_ptc_lock, flags); | ||
145 | } | ||
146 | #endif | ||
147 | |||
148 | struct ptc_stats { | ||
149 | unsigned long ptc_l; | ||
150 | unsigned long change_rid; | ||
151 | unsigned long shub_ptc_flushes; | ||
152 | unsigned long nodes_flushed; | ||
153 | unsigned long deadlocks; | ||
154 | unsigned long lock_itc_clocks; | ||
155 | unsigned long shub_itc_clocks; | ||
156 | unsigned long shub_itc_clocks_max; | ||
157 | }; | ||
48 | 158 | ||
49 | static inline unsigned long wait_piowc(void) | 159 | static inline unsigned long wait_piowc(void) |
50 | { | 160 | { |
@@ -89,9 +199,9 @@ void | |||
89 | sn2_global_tlb_purge(unsigned long start, unsigned long end, | 199 | sn2_global_tlb_purge(unsigned long start, unsigned long end, |
90 | unsigned long nbits) | 200 | unsigned long nbits) |
91 | { | 201 | { |
92 | int i, shub1, cnode, mynasid, cpu, lcpu = 0, nasid, flushed = 0; | 202 | int i, opt, shub1, cnode, mynasid, cpu, lcpu = 0, nasid, flushed = 0; |
93 | volatile unsigned long *ptc0, *ptc1; | 203 | volatile unsigned long *ptc0, *ptc1; |
94 | unsigned long flags = 0, data0 = 0, data1 = 0; | 204 | unsigned long itc, itc2, flags, data0 = 0, data1 = 0; |
95 | struct mm_struct *mm = current->active_mm; | 205 | struct mm_struct *mm = current->active_mm; |
96 | short nasids[MAX_NUMNODES], nix; | 206 | short nasids[MAX_NUMNODES], nix; |
97 | nodemask_t nodes_flushed; | 207 | nodemask_t nodes_flushed; |
@@ -114,16 +224,19 @@ sn2_global_tlb_purge(unsigned long start, unsigned long end, | |||
114 | start += (1UL << nbits); | 224 | start += (1UL << nbits); |
115 | } while (start < end); | 225 | } while (start < end); |
116 | ia64_srlz_i(); | 226 | ia64_srlz_i(); |
227 | __get_cpu_var(ptcstats).ptc_l++; | ||
117 | preempt_enable(); | 228 | preempt_enable(); |
118 | return; | 229 | return; |
119 | } | 230 | } |
120 | 231 | ||
121 | if (atomic_read(&mm->mm_users) == 1) { | 232 | if (atomic_read(&mm->mm_users) == 1) { |
122 | flush_tlb_mm(mm); | 233 | flush_tlb_mm(mm); |
234 | __get_cpu_var(ptcstats).change_rid++; | ||
123 | preempt_enable(); | 235 | preempt_enable(); |
124 | return; | 236 | return; |
125 | } | 237 | } |
126 | 238 | ||
239 | itc = ia64_get_itc(); | ||
127 | nix = 0; | 240 | nix = 0; |
128 | for_each_node_mask(cnode, nodes_flushed) | 241 | for_each_node_mask(cnode, nodes_flushed) |
129 | nasids[nix++] = cnodeid_to_nasid(cnode); | 242 | nasids[nix++] = cnodeid_to_nasid(cnode); |
@@ -148,7 +261,12 @@ sn2_global_tlb_purge(unsigned long start, unsigned long end, | |||
148 | 261 | ||
149 | mynasid = get_nasid(); | 262 | mynasid = get_nasid(); |
150 | 263 | ||
151 | spin_lock_irqsave(&sn2_global_ptc_lock, flags); | 264 | itc = ia64_get_itc(); |
265 | opt = ptc_lock(&flags); | ||
266 | itc2 = ia64_get_itc(); | ||
267 | __get_cpu_var(ptcstats).lock_itc_clocks += itc2 - itc; | ||
268 | __get_cpu_var(ptcstats).shub_ptc_flushes++; | ||
269 | __get_cpu_var(ptcstats).nodes_flushed += nix; | ||
152 | 270 | ||
153 | do { | 271 | do { |
154 | if (shub1) | 272 | if (shub1) |
@@ -157,7 +275,7 @@ sn2_global_tlb_purge(unsigned long start, unsigned long end, | |||
157 | data0 = (data0 & ~SH2_PTC_ADDR_MASK) | (start & SH2_PTC_ADDR_MASK); | 275 | data0 = (data0 & ~SH2_PTC_ADDR_MASK) | (start & SH2_PTC_ADDR_MASK); |
158 | for (i = 0; i < nix; i++) { | 276 | for (i = 0; i < nix; i++) { |
159 | nasid = nasids[i]; | 277 | nasid = nasids[i]; |
160 | if (unlikely(nasid == mynasid)) { | 278 | if ((!(sn2_ptctest & 3)) && unlikely(nasid == mynasid)) { |
161 | ia64_ptcga(start, nbits << 2); | 279 | ia64_ptcga(start, nbits << 2); |
162 | ia64_srlz_i(); | 280 | ia64_srlz_i(); |
163 | } else { | 281 | } else { |
@@ -169,18 +287,22 @@ sn2_global_tlb_purge(unsigned long start, unsigned long end, | |||
169 | flushed = 1; | 287 | flushed = 1; |
170 | } | 288 | } |
171 | } | 289 | } |
172 | |||
173 | if (flushed | 290 | if (flushed |
174 | && (wait_piowc() & | 291 | && (wait_piowc() & |
175 | SH_PIO_WRITE_STATUS_WRITE_DEADLOCK_MASK)) { | 292 | (SH_PIO_WRITE_STATUS_WRITE_DEADLOCK_MASK))) { |
176 | sn2_ptc_deadlock_recovery(ptc0, data0, ptc1, data1); | 293 | sn2_ptc_deadlock_recovery(nasids, nix, mynasid, ptc0, data0, ptc1, data1); |
177 | } | 294 | } |
178 | 295 | ||
179 | start += (1UL << nbits); | 296 | start += (1UL << nbits); |
180 | 297 | ||
181 | } while (start < end); | 298 | } while (start < end); |
182 | 299 | ||
183 | spin_unlock_irqrestore(&sn2_global_ptc_lock, flags); | 300 | itc2 = ia64_get_itc() - itc2; |
301 | __get_cpu_var(ptcstats).shub_itc_clocks += itc2; | ||
302 | if (itc2 > __get_cpu_var(ptcstats).shub_itc_clocks_max) | ||
303 | __get_cpu_var(ptcstats).shub_itc_clocks_max = itc2; | ||
304 | |||
305 | ptc_unlock(flags, opt); | ||
184 | 306 | ||
185 | preempt_enable(); | 307 | preempt_enable(); |
186 | } | 308 | } |
@@ -192,31 +314,29 @@ sn2_global_tlb_purge(unsigned long start, unsigned long end, | |||
192 | * TLB flush transaction. The recovery sequence is somewhat tricky & is | 314 | * TLB flush transaction. The recovery sequence is somewhat tricky & is |
193 | * coded in assembly language. | 315 | * coded in assembly language. |
194 | */ | 316 | */ |
195 | void sn2_ptc_deadlock_recovery(volatile unsigned long *ptc0, unsigned long data0, | 317 | void sn2_ptc_deadlock_recovery(short *nasids, short nix, int mynasid, volatile unsigned long *ptc0, unsigned long data0, |
196 | volatile unsigned long *ptc1, unsigned long data1) | 318 | volatile unsigned long *ptc1, unsigned long data1) |
197 | { | 319 | { |
198 | extern void sn2_ptc_deadlock_recovery_core(volatile unsigned long *, unsigned long, | 320 | extern void sn2_ptc_deadlock_recovery_core(volatile unsigned long *, unsigned long, |
199 | volatile unsigned long *, unsigned long, volatile unsigned long *, unsigned long); | 321 | volatile unsigned long *, unsigned long, volatile unsigned long *, unsigned long); |
200 | int cnode, mycnode, nasid; | 322 | short nasid, i; |
201 | volatile unsigned long *piows; | 323 | unsigned long *piows, zeroval; |
202 | volatile unsigned long zeroval; | ||
203 | 324 | ||
204 | sn2_ptc_deadlock_count++; | 325 | __get_cpu_var(ptcstats).deadlocks++; |
205 | 326 | ||
206 | piows = pda->pio_write_status_addr; | 327 | piows = (unsigned long *) pda->pio_write_status_addr; |
207 | zeroval = pda->pio_write_status_val; | 328 | zeroval = pda->pio_write_status_val; |
208 | 329 | ||
209 | mycnode = numa_node_id(); | 330 | for (i=0; i < nix; i++) { |
210 | 331 | nasid = nasids[i]; | |
211 | for_each_online_node(cnode) { | 332 | if (!(sn2_ptctest & 3) && nasid == mynasid) |
212 | if (is_headless_node(cnode) || cnode == mycnode) | ||
213 | continue; | 333 | continue; |
214 | nasid = cnodeid_to_nasid(cnode); | ||
215 | ptc0 = CHANGE_NASID(nasid, ptc0); | 334 | ptc0 = CHANGE_NASID(nasid, ptc0); |
216 | if (ptc1) | 335 | if (ptc1) |
217 | ptc1 = CHANGE_NASID(nasid, ptc1); | 336 | ptc1 = CHANGE_NASID(nasid, ptc1); |
218 | sn2_ptc_deadlock_recovery_core(ptc0, data0, ptc1, data1, piows, zeroval); | 337 | sn2_ptc_deadlock_recovery_core(ptc0, data0, ptc1, data1, piows, zeroval); |
219 | } | 338 | } |
339 | |||
220 | } | 340 | } |
221 | 341 | ||
222 | /** | 342 | /** |
@@ -293,3 +413,93 @@ void sn2_send_IPI(int cpuid, int vector, int delivery_mode, int redirect) | |||
293 | 413 | ||
294 | sn_send_IPI_phys(nasid, physid, vector, delivery_mode); | 414 | sn_send_IPI_phys(nasid, physid, vector, delivery_mode); |
295 | } | 415 | } |
416 | |||
417 | #ifdef CONFIG_PROC_FS | ||
418 | |||
419 | #define PTC_BASENAME "sgi_sn/ptc_statistics" | ||
420 | |||
421 | static void *sn2_ptc_seq_start(struct seq_file *file, loff_t * offset) | ||
422 | { | ||
423 | if (*offset < NR_CPUS) | ||
424 | return offset; | ||
425 | return NULL; | ||
426 | } | ||
427 | |||
428 | static void *sn2_ptc_seq_next(struct seq_file *file, void *data, loff_t * offset) | ||
429 | { | ||
430 | (*offset)++; | ||
431 | if (*offset < NR_CPUS) | ||
432 | return offset; | ||
433 | return NULL; | ||
434 | } | ||
435 | |||
436 | static void sn2_ptc_seq_stop(struct seq_file *file, void *data) | ||
437 | { | ||
438 | } | ||
439 | |||
440 | static int sn2_ptc_seq_show(struct seq_file *file, void *data) | ||
441 | { | ||
442 | struct ptc_stats *stat; | ||
443 | int cpu; | ||
444 | |||
445 | cpu = *(loff_t *) data; | ||
446 | |||
447 | if (!cpu) { | ||
448 | seq_printf(file, "# ptc_l change_rid shub_ptc_flushes shub_nodes_flushed deadlocks lock_nsec shub_nsec shub_nsec_max\n"); | ||
449 | seq_printf(file, "# ptctest %d\n", sn2_ptctest); | ||
450 | } | ||
451 | |||
452 | if (cpu < NR_CPUS && cpu_online(cpu)) { | ||
453 | stat = &per_cpu(ptcstats, cpu); | ||
454 | seq_printf(file, "cpu %d %ld %ld %ld %ld %ld %ld %ld %ld\n", cpu, stat->ptc_l, | ||
455 | stat->change_rid, stat->shub_ptc_flushes, stat->nodes_flushed, | ||
456 | stat->deadlocks, | ||
457 | 1000 * stat->lock_itc_clocks / per_cpu(cpu_info, cpu).cyc_per_usec, | ||
458 | 1000 * stat->shub_itc_clocks / per_cpu(cpu_info, cpu).cyc_per_usec, | ||
459 | 1000 * stat->shub_itc_clocks_max / per_cpu(cpu_info, cpu).cyc_per_usec); | ||
460 | } | ||
461 | |||
462 | return 0; | ||
463 | } | ||
464 | |||
465 | static struct seq_operations sn2_ptc_seq_ops = { | ||
466 | .start = sn2_ptc_seq_start, | ||
467 | .next = sn2_ptc_seq_next, | ||
468 | .stop = sn2_ptc_seq_stop, | ||
469 | .show = sn2_ptc_seq_show | ||
470 | }; | ||
471 | |||
472 | int sn2_ptc_proc_open(struct inode *inode, struct file *file) | ||
473 | { | ||
474 | return seq_open(file, &sn2_ptc_seq_ops); | ||
475 | } | ||
476 | |||
477 | static struct file_operations proc_sn2_ptc_operations = { | ||
478 | .open = sn2_ptc_proc_open, | ||
479 | .read = seq_read, | ||
480 | .llseek = seq_lseek, | ||
481 | .release = seq_release, | ||
482 | }; | ||
483 | |||
484 | static struct proc_dir_entry *proc_sn2_ptc; | ||
485 | |||
486 | static int __init sn2_ptc_init(void) | ||
487 | { | ||
488 | if (!(proc_sn2_ptc = create_proc_entry(PTC_BASENAME, 0444, NULL))) { | ||
489 | printk(KERN_ERR "unable to create %s proc entry", PTC_BASENAME); | ||
490 | return -EINVAL; | ||
491 | } | ||
492 | proc_sn2_ptc->proc_fops = &proc_sn2_ptc_operations; | ||
493 | spin_lock_init(&sn2_global_ptc_lock); | ||
494 | return 0; | ||
495 | } | ||
496 | |||
497 | static void __exit sn2_ptc_exit(void) | ||
498 | { | ||
499 | remove_proc_entry(PTC_BASENAME, NULL); | ||
500 | } | ||
501 | |||
502 | module_init(sn2_ptc_init); | ||
503 | module_exit(sn2_ptc_exit); | ||
504 | #endif /* CONFIG_PROC_FS */ | ||
505 | |||
diff --git a/arch/ia64/sn/kernel/sn2/sn_hwperf.c b/arch/ia64/sn/kernel/sn2/sn_hwperf.c index 833e700fdac9..0513aacac8c1 100644 --- a/arch/ia64/sn/kernel/sn2/sn_hwperf.c +++ b/arch/ia64/sn/kernel/sn2/sn_hwperf.c | |||
@@ -36,7 +36,6 @@ | |||
36 | #include <asm/topology.h> | 36 | #include <asm/topology.h> |
37 | #include <asm/smp.h> | 37 | #include <asm/smp.h> |
38 | #include <asm/semaphore.h> | 38 | #include <asm/semaphore.h> |
39 | #include <asm/segment.h> | ||
40 | #include <asm/uaccess.h> | 39 | #include <asm/uaccess.h> |
41 | #include <asm/sal.h> | 40 | #include <asm/sal.h> |
42 | #include <asm/sn/io.h> | 41 | #include <asm/sn/io.h> |
@@ -59,7 +58,7 @@ static int sn_hwperf_enum_objects(int *nobj, struct sn_hwperf_object_info **ret) | |||
59 | struct sn_hwperf_object_info *objbuf = NULL; | 58 | struct sn_hwperf_object_info *objbuf = NULL; |
60 | 59 | ||
61 | if ((e = sn_hwperf_init()) < 0) { | 60 | if ((e = sn_hwperf_init()) < 0) { |
62 | printk("sn_hwperf_init failed: err %d\n", e); | 61 | printk(KERN_ERR "sn_hwperf_init failed: err %d\n", e); |
63 | goto out; | 62 | goto out; |
64 | } | 63 | } |
65 | 64 | ||
@@ -111,7 +110,7 @@ static int sn_hwperf_geoid_to_cnode(char *location) | |||
111 | if (sn_hwperf_location_to_bpos(location, &rack, &bay, &slot, &slab)) | 110 | if (sn_hwperf_location_to_bpos(location, &rack, &bay, &slot, &slab)) |
112 | return -1; | 111 | return -1; |
113 | 112 | ||
114 | for (cnode = 0; cnode < numionodes; cnode++) { | 113 | for_each_node(cnode) { |
115 | geoid = cnodeid_get_geoid(cnode); | 114 | geoid = cnodeid_get_geoid(cnode); |
116 | module_id = geo_module(geoid); | 115 | module_id = geo_module(geoid); |
117 | this_rack = MODULE_GET_RACK(module_id); | 116 | this_rack = MODULE_GET_RACK(module_id); |
@@ -124,11 +123,13 @@ static int sn_hwperf_geoid_to_cnode(char *location) | |||
124 | } | 123 | } |
125 | } | 124 | } |
126 | 125 | ||
127 | return cnode < numionodes ? cnode : -1; | 126 | return node_possible(cnode) ? cnode : -1; |
128 | } | 127 | } |
129 | 128 | ||
130 | static int sn_hwperf_obj_to_cnode(struct sn_hwperf_object_info * obj) | 129 | static int sn_hwperf_obj_to_cnode(struct sn_hwperf_object_info * obj) |
131 | { | 130 | { |
131 | if (!SN_HWPERF_IS_NODE(obj) && !SN_HWPERF_IS_IONODE(obj)) | ||
132 | BUG(); | ||
132 | if (!obj->sn_hwp_this_part) | 133 | if (!obj->sn_hwp_this_part) |
133 | return -1; | 134 | return -1; |
134 | return sn_hwperf_geoid_to_cnode(obj->location); | 135 | return sn_hwperf_geoid_to_cnode(obj->location); |
@@ -174,31 +175,199 @@ static const char *sn_hwperf_get_slabname(struct sn_hwperf_object_info *obj, | |||
174 | return slabname; | 175 | return slabname; |
175 | } | 176 | } |
176 | 177 | ||
177 | static void print_pci_topology(struct seq_file *s, | 178 | static void print_pci_topology(struct seq_file *s) |
178 | struct sn_hwperf_object_info *obj, int *ordinal, | 179 | { |
179 | u64 rack, u64 bay, u64 slot, u64 slab) | 180 | char *p; |
181 | size_t sz; | ||
182 | int e; | ||
183 | |||
184 | for (sz = PAGE_SIZE; sz < 16 * PAGE_SIZE; sz += PAGE_SIZE) { | ||
185 | if (!(p = (char *)kmalloc(sz, GFP_KERNEL))) | ||
186 | break; | ||
187 | e = ia64_sn_ioif_get_pci_topology(__pa(p), sz); | ||
188 | if (e == SALRET_OK) | ||
189 | seq_puts(s, p); | ||
190 | kfree(p); | ||
191 | if (e == SALRET_OK || e == SALRET_NOT_IMPLEMENTED) | ||
192 | break; | ||
193 | } | ||
194 | } | ||
195 | |||
196 | static inline int sn_hwperf_has_cpus(cnodeid_t node) | ||
197 | { | ||
198 | return node_online(node) && nr_cpus_node(node); | ||
199 | } | ||
200 | |||
201 | static inline int sn_hwperf_has_mem(cnodeid_t node) | ||
202 | { | ||
203 | return node_online(node) && NODE_DATA(node)->node_present_pages; | ||
204 | } | ||
205 | |||
206 | static struct sn_hwperf_object_info * | ||
207 | sn_hwperf_findobj_id(struct sn_hwperf_object_info *objbuf, | ||
208 | int nobj, int id) | ||
180 | { | 209 | { |
181 | char *p1; | 210 | int i; |
182 | char *p2; | 211 | struct sn_hwperf_object_info *p = objbuf; |
183 | char *pg; | 212 | |
184 | 213 | for (i=0; i < nobj; i++, p++) { | |
185 | if (!(pg = (char *)get_zeroed_page(GFP_KERNEL))) | 214 | if (p->id == id) |
186 | return; /* ignore */ | 215 | return p; |
187 | if (ia64_sn_ioif_get_pci_topology(rack, bay, slot, slab, | 216 | } |
188 | __pa(pg), PAGE_SIZE) == SN_HWPERF_OP_OK) { | 217 | |
189 | for (p1=pg; *p1 && p1 < pg + PAGE_SIZE;) { | 218 | return NULL; |
190 | if (!(p2 = strchr(p1, '\n'))) | 219 | |
220 | } | ||
221 | |||
222 | static int sn_hwperf_get_nearest_node_objdata(struct sn_hwperf_object_info *objbuf, | ||
223 | int nobj, cnodeid_t node, cnodeid_t *near_mem_node, cnodeid_t *near_cpu_node) | ||
224 | { | ||
225 | int e; | ||
226 | struct sn_hwperf_object_info *nodeobj = NULL; | ||
227 | struct sn_hwperf_object_info *op; | ||
228 | struct sn_hwperf_object_info *dest; | ||
229 | struct sn_hwperf_object_info *router; | ||
230 | struct sn_hwperf_port_info ptdata[16]; | ||
231 | int sz, i, j; | ||
232 | cnodeid_t c; | ||
233 | int found_mem = 0; | ||
234 | int found_cpu = 0; | ||
235 | |||
236 | if (!node_possible(node)) | ||
237 | return -EINVAL; | ||
238 | |||
239 | if (sn_hwperf_has_cpus(node)) { | ||
240 | if (near_cpu_node) | ||
241 | *near_cpu_node = node; | ||
242 | found_cpu++; | ||
243 | } | ||
244 | |||
245 | if (sn_hwperf_has_mem(node)) { | ||
246 | if (near_mem_node) | ||
247 | *near_mem_node = node; | ||
248 | found_mem++; | ||
249 | } | ||
250 | |||
251 | if (found_cpu && found_mem) | ||
252 | return 0; /* trivially successful */ | ||
253 | |||
254 | /* find the argument node object */ | ||
255 | for (i=0, op=objbuf; i < nobj; i++, op++) { | ||
256 | if (!SN_HWPERF_IS_NODE(op) && !SN_HWPERF_IS_IONODE(op)) | ||
257 | continue; | ||
258 | if (node == sn_hwperf_obj_to_cnode(op)) { | ||
259 | nodeobj = op; | ||
260 | break; | ||
261 | } | ||
262 | } | ||
263 | if (!nodeobj) { | ||
264 | e = -ENOENT; | ||
265 | goto err; | ||
266 | } | ||
267 | |||
268 | /* get it's interconnect topology */ | ||
269 | sz = op->ports * sizeof(struct sn_hwperf_port_info); | ||
270 | if (sz > sizeof(ptdata)) | ||
271 | BUG(); | ||
272 | e = ia64_sn_hwperf_op(sn_hwperf_master_nasid, | ||
273 | SN_HWPERF_ENUM_PORTS, nodeobj->id, sz, | ||
274 | (u64)&ptdata, 0, 0, NULL); | ||
275 | if (e != SN_HWPERF_OP_OK) { | ||
276 | e = -EINVAL; | ||
277 | goto err; | ||
278 | } | ||
279 | |||
280 | /* find nearest node with cpus and nearest memory */ | ||
281 | for (router=NULL, j=0; j < op->ports; j++) { | ||
282 | dest = sn_hwperf_findobj_id(objbuf, nobj, ptdata[j].conn_id); | ||
283 | if (!dest || SN_HWPERF_FOREIGN(dest) || | ||
284 | !SN_HWPERF_IS_NODE(dest) || SN_HWPERF_IS_IONODE(dest)) { | ||
285 | continue; | ||
286 | } | ||
287 | c = sn_hwperf_obj_to_cnode(dest); | ||
288 | if (!found_cpu && sn_hwperf_has_cpus(c)) { | ||
289 | if (near_cpu_node) | ||
290 | *near_cpu_node = c; | ||
291 | found_cpu++; | ||
292 | } | ||
293 | if (!found_mem && sn_hwperf_has_mem(c)) { | ||
294 | if (near_mem_node) | ||
295 | *near_mem_node = c; | ||
296 | found_mem++; | ||
297 | } | ||
298 | if (SN_HWPERF_IS_ROUTER(dest)) | ||
299 | router = dest; | ||
300 | } | ||
301 | |||
302 | if (router && (!found_cpu || !found_mem)) { | ||
303 | /* search for a node connected to the same router */ | ||
304 | sz = router->ports * sizeof(struct sn_hwperf_port_info); | ||
305 | if (sz > sizeof(ptdata)) | ||
306 | BUG(); | ||
307 | e = ia64_sn_hwperf_op(sn_hwperf_master_nasid, | ||
308 | SN_HWPERF_ENUM_PORTS, router->id, sz, | ||
309 | (u64)&ptdata, 0, 0, NULL); | ||
310 | if (e != SN_HWPERF_OP_OK) { | ||
311 | e = -EINVAL; | ||
312 | goto err; | ||
313 | } | ||
314 | for (j=0; j < router->ports; j++) { | ||
315 | dest = sn_hwperf_findobj_id(objbuf, nobj, | ||
316 | ptdata[j].conn_id); | ||
317 | if (!dest || dest->id == node || | ||
318 | SN_HWPERF_FOREIGN(dest) || | ||
319 | !SN_HWPERF_IS_NODE(dest) || | ||
320 | SN_HWPERF_IS_IONODE(dest)) { | ||
321 | continue; | ||
322 | } | ||
323 | c = sn_hwperf_obj_to_cnode(dest); | ||
324 | if (!found_cpu && sn_hwperf_has_cpus(c)) { | ||
325 | if (near_cpu_node) | ||
326 | *near_cpu_node = c; | ||
327 | found_cpu++; | ||
328 | } | ||
329 | if (!found_mem && sn_hwperf_has_mem(c)) { | ||
330 | if (near_mem_node) | ||
331 | *near_mem_node = c; | ||
332 | found_mem++; | ||
333 | } | ||
334 | if (found_cpu && found_mem) | ||
335 | break; | ||
336 | } | ||
337 | } | ||
338 | |||
339 | if (!found_cpu || !found_mem) { | ||
340 | /* resort to _any_ node with CPUs and memory */ | ||
341 | for (i=0, op=objbuf; i < nobj; i++, op++) { | ||
342 | if (SN_HWPERF_FOREIGN(op) || | ||
343 | SN_HWPERF_IS_IONODE(op) || | ||
344 | !SN_HWPERF_IS_NODE(op)) { | ||
345 | continue; | ||
346 | } | ||
347 | c = sn_hwperf_obj_to_cnode(op); | ||
348 | if (!found_cpu && sn_hwperf_has_cpus(c)) { | ||
349 | if (near_cpu_node) | ||
350 | *near_cpu_node = c; | ||
351 | found_cpu++; | ||
352 | } | ||
353 | if (!found_mem && sn_hwperf_has_mem(c)) { | ||
354 | if (near_mem_node) | ||
355 | *near_mem_node = c; | ||
356 | found_mem++; | ||
357 | } | ||
358 | if (found_cpu && found_mem) | ||
191 | break; | 359 | break; |
192 | *p2 = '\0'; | ||
193 | seq_printf(s, "pcibus %d %s-%s\n", | ||
194 | *ordinal, obj->location, p1); | ||
195 | (*ordinal)++; | ||
196 | p1 = p2 + 1; | ||
197 | } | 360 | } |
198 | } | 361 | } |
199 | free_page((unsigned long)pg); | 362 | |
363 | if (!found_cpu || !found_mem) | ||
364 | e = -ENODATA; | ||
365 | |||
366 | err: | ||
367 | return e; | ||
200 | } | 368 | } |
201 | 369 | ||
370 | |||
202 | static int sn_topology_show(struct seq_file *s, void *d) | 371 | static int sn_topology_show(struct seq_file *s, void *d) |
203 | { | 372 | { |
204 | int sz; | 373 | int sz; |
@@ -215,7 +384,6 @@ static int sn_topology_show(struct seq_file *s, void *d) | |||
215 | struct sn_hwperf_object_info *p; | 384 | struct sn_hwperf_object_info *p; |
216 | struct sn_hwperf_object_info *obj = d; /* this object */ | 385 | struct sn_hwperf_object_info *obj = d; /* this object */ |
217 | struct sn_hwperf_object_info *objs = s->private; /* all objects */ | 386 | struct sn_hwperf_object_info *objs = s->private; /* all objects */ |
218 | int rack, bay, slot, slab; | ||
219 | u8 shubtype; | 387 | u8 shubtype; |
220 | u8 system_size; | 388 | u8 system_size; |
221 | u8 sharing_size; | 389 | u8 sharing_size; |
@@ -225,7 +393,6 @@ static int sn_topology_show(struct seq_file *s, void *d) | |||
225 | u8 region_size; | 393 | u8 region_size; |
226 | u16 nasid_mask; | 394 | u16 nasid_mask; |
227 | int nasid_msb; | 395 | int nasid_msb; |
228 | int pci_bus_ordinal = 0; | ||
229 | 396 | ||
230 | if (obj == objs) { | 397 | if (obj == objs) { |
231 | seq_printf(s, "# sn_topology version 2\n"); | 398 | seq_printf(s, "# sn_topology version 2\n"); |
@@ -253,6 +420,8 @@ static int sn_topology_show(struct seq_file *s, void *d) | |||
253 | shubtype ? "shub2" : "shub1", | 420 | shubtype ? "shub2" : "shub1", |
254 | (u64)nasid_mask << nasid_shift, nasid_msb, nasid_shift, | 421 | (u64)nasid_mask << nasid_shift, nasid_msb, nasid_shift, |
255 | system_size, sharing_size, coher, region_size); | 422 | system_size, sharing_size, coher, region_size); |
423 | |||
424 | print_pci_topology(s); | ||
256 | } | 425 | } |
257 | 426 | ||
258 | if (SN_HWPERF_FOREIGN(obj)) { | 427 | if (SN_HWPERF_FOREIGN(obj)) { |
@@ -272,11 +441,24 @@ static int sn_topology_show(struct seq_file *s, void *d) | |||
272 | if (!SN_HWPERF_IS_NODE(obj) && !SN_HWPERF_IS_IONODE(obj)) | 441 | if (!SN_HWPERF_IS_NODE(obj) && !SN_HWPERF_IS_IONODE(obj)) |
273 | seq_putc(s, '\n'); | 442 | seq_putc(s, '\n'); |
274 | else { | 443 | else { |
444 | cnodeid_t near_mem = -1; | ||
445 | cnodeid_t near_cpu = -1; | ||
446 | |||
275 | seq_printf(s, ", nasid 0x%x", cnodeid_to_nasid(ordinal)); | 447 | seq_printf(s, ", nasid 0x%x", cnodeid_to_nasid(ordinal)); |
276 | for (i=0; i < numionodes; i++) { | 448 | |
277 | seq_printf(s, i ? ":%d" : ", dist %d", | 449 | if (sn_hwperf_get_nearest_node_objdata(objs, sn_hwperf_obj_cnt, |
278 | node_distance(ordinal, i)); | 450 | ordinal, &near_mem, &near_cpu) == 0) { |
451 | seq_printf(s, ", near_mem_nodeid %d, near_cpu_nodeid %d", | ||
452 | near_mem, near_cpu); | ||
453 | } | ||
454 | |||
455 | if (!SN_HWPERF_IS_IONODE(obj)) { | ||
456 | for_each_online_node(i) { | ||
457 | seq_printf(s, i ? ":%d" : ", dist %d", | ||
458 | node_distance(ordinal, i)); | ||
459 | } | ||
279 | } | 460 | } |
461 | |||
280 | seq_putc(s, '\n'); | 462 | seq_putc(s, '\n'); |
281 | 463 | ||
282 | /* | 464 | /* |
@@ -300,17 +482,6 @@ static int sn_topology_show(struct seq_file *s, void *d) | |||
300 | seq_putc(s, '\n'); | 482 | seq_putc(s, '\n'); |
301 | } | 483 | } |
302 | } | 484 | } |
303 | |||
304 | /* | ||
305 | * PCI busses attached to this node, if any | ||
306 | */ | ||
307 | if (sn_hwperf_location_to_bpos(obj->location, | ||
308 | &rack, &bay, &slot, &slab)) { | ||
309 | /* export pci bus info */ | ||
310 | print_pci_topology(s, obj, &pci_bus_ordinal, | ||
311 | rack, bay, slot, slab); | ||
312 | |||
313 | } | ||
314 | } | 485 | } |
315 | 486 | ||
316 | if (obj->ports) { | 487 | if (obj->ports) { |
@@ -572,6 +743,8 @@ sn_hwperf_ioctl(struct inode *in, struct file *fp, u32 op, u64 arg) | |||
572 | if ((r = sn_hwperf_enum_objects(&nobj, &objs)) == 0) { | 743 | if ((r = sn_hwperf_enum_objects(&nobj, &objs)) == 0) { |
573 | memset(p, 0, a.sz); | 744 | memset(p, 0, a.sz); |
574 | for (i = 0; i < nobj; i++) { | 745 | for (i = 0; i < nobj; i++) { |
746 | if (!SN_HWPERF_IS_NODE(objs + i)) | ||
747 | continue; | ||
575 | node = sn_hwperf_obj_to_cnode(objs + i); | 748 | node = sn_hwperf_obj_to_cnode(objs + i); |
576 | for_each_online_cpu(j) { | 749 | for_each_online_cpu(j) { |
577 | if (node != cpu_to_node(j)) | 750 | if (node != cpu_to_node(j)) |
@@ -598,7 +771,7 @@ sn_hwperf_ioctl(struct inode *in, struct file *fp, u32 op, u64 arg) | |||
598 | 771 | ||
599 | case SN_HWPERF_GET_NODE_NASID: | 772 | case SN_HWPERF_GET_NODE_NASID: |
600 | if (a.sz != sizeof(u64) || | 773 | if (a.sz != sizeof(u64) || |
601 | (node = a.arg) < 0 || node >= numionodes) { | 774 | (node = a.arg) < 0 || !node_possible(node)) { |
602 | r = -EINVAL; | 775 | r = -EINVAL; |
603 | goto error; | 776 | goto error; |
604 | } | 777 | } |
@@ -627,6 +800,14 @@ sn_hwperf_ioctl(struct inode *in, struct file *fp, u32 op, u64 arg) | |||
627 | vfree(objs); | 800 | vfree(objs); |
628 | goto error; | 801 | goto error; |
629 | } | 802 | } |
803 | |||
804 | if (!SN_HWPERF_IS_NODE(objs + i) && | ||
805 | !SN_HWPERF_IS_IONODE(objs + i)) { | ||
806 | r = -ENOENT; | ||
807 | vfree(objs); | ||
808 | goto error; | ||
809 | } | ||
810 | |||
630 | *(u64 *)p = (u64)sn_hwperf_obj_to_cnode(objs + i); | 811 | *(u64 *)p = (u64)sn_hwperf_obj_to_cnode(objs + i); |
631 | vfree(objs); | 812 | vfree(objs); |
632 | } | 813 | } |
@@ -692,6 +873,7 @@ static int sn_hwperf_init(void) | |||
692 | 873 | ||
693 | /* single threaded, once-only initialization */ | 874 | /* single threaded, once-only initialization */ |
694 | down(&sn_hwperf_init_mutex); | 875 | down(&sn_hwperf_init_mutex); |
876 | |||
695 | if (sn_hwperf_salheap) { | 877 | if (sn_hwperf_salheap) { |
696 | up(&sn_hwperf_init_mutex); | 878 | up(&sn_hwperf_init_mutex); |
697 | return e; | 879 | return e; |
@@ -742,19 +924,6 @@ out: | |||
742 | sn_hwperf_salheap = NULL; | 924 | sn_hwperf_salheap = NULL; |
743 | sn_hwperf_obj_cnt = 0; | 925 | sn_hwperf_obj_cnt = 0; |
744 | } | 926 | } |
745 | |||
746 | if (!e) { | ||
747 | /* | ||
748 | * Register a dynamic misc device for ioctl. Platforms | ||
749 | * supporting hotplug will create /dev/sn_hwperf, else | ||
750 | * user can to look up the minor number in /proc/misc. | ||
751 | */ | ||
752 | if ((e = misc_register(&sn_hwperf_dev)) != 0) { | ||
753 | printk(KERN_ERR "sn_hwperf_init: misc register " | ||
754 | "for \"sn_hwperf\" failed, err %d\n", e); | ||
755 | } | ||
756 | } | ||
757 | |||
758 | up(&sn_hwperf_init_mutex); | 927 | up(&sn_hwperf_init_mutex); |
759 | return e; | 928 | return e; |
760 | } | 929 | } |
@@ -782,3 +951,41 @@ int sn_topology_release(struct inode *inode, struct file *file) | |||
782 | vfree(seq->private); | 951 | vfree(seq->private); |
783 | return seq_release(inode, file); | 952 | return seq_release(inode, file); |
784 | } | 953 | } |
954 | |||
955 | int sn_hwperf_get_nearest_node(cnodeid_t node, | ||
956 | cnodeid_t *near_mem_node, cnodeid_t *near_cpu_node) | ||
957 | { | ||
958 | int e; | ||
959 | int nobj; | ||
960 | struct sn_hwperf_object_info *objbuf; | ||
961 | |||
962 | if ((e = sn_hwperf_enum_objects(&nobj, &objbuf)) == 0) { | ||
963 | e = sn_hwperf_get_nearest_node_objdata(objbuf, nobj, | ||
964 | node, near_mem_node, near_cpu_node); | ||
965 | vfree(objbuf); | ||
966 | } | ||
967 | |||
968 | return e; | ||
969 | } | ||
970 | |||
971 | static int __devinit sn_hwperf_misc_register_init(void) | ||
972 | { | ||
973 | int e; | ||
974 | |||
975 | sn_hwperf_init(); | ||
976 | |||
977 | /* | ||
978 | * Register a dynamic misc device for hwperf ioctls. Platforms | ||
979 | * supporting hotplug will create /dev/sn_hwperf, else user | ||
980 | * can to look up the minor number in /proc/misc. | ||
981 | */ | ||
982 | if ((e = misc_register(&sn_hwperf_dev)) != 0) { | ||
983 | printk(KERN_ERR "sn_hwperf_misc_register_init: failed to " | ||
984 | "register misc device for \"%s\"\n", sn_hwperf_dev.name); | ||
985 | } | ||
986 | |||
987 | return e; | ||
988 | } | ||
989 | |||
990 | device_initcall(sn_hwperf_misc_register_init); /* after misc_init() */ | ||
991 | EXPORT_SYMBOL(sn_hwperf_get_nearest_node); | ||
diff --git a/arch/ia64/sn/kernel/sn2/sn_proc_fs.c b/arch/ia64/sn/kernel/sn2/sn_proc_fs.c index 6a80fca807b9..51bf82720d99 100644 --- a/arch/ia64/sn/kernel/sn2/sn_proc_fs.c +++ b/arch/ia64/sn/kernel/sn2/sn_proc_fs.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * License. See the file "COPYING" in the main directory of this archive | 3 | * License. See the file "COPYING" in the main directory of this archive |
4 | * for more details. | 4 | * for more details. |
5 | * | 5 | * |
6 | * Copyright (C) 2000-2004 Silicon Graphics, Inc. All rights reserved. | 6 | * Copyright (C) 2000-2005 Silicon Graphics, Inc. All rights reserved. |
7 | */ | 7 | */ |
8 | #include <linux/config.h> | 8 | #include <linux/config.h> |
9 | #include <asm/uaccess.h> | 9 | #include <asm/uaccess.h> |
@@ -15,7 +15,7 @@ | |||
15 | 15 | ||
16 | static int partition_id_show(struct seq_file *s, void *p) | 16 | static int partition_id_show(struct seq_file *s, void *p) |
17 | { | 17 | { |
18 | seq_printf(s, "%d\n", sn_local_partid()); | 18 | seq_printf(s, "%d\n", sn_partition_id); |
19 | return 0; | 19 | return 0; |
20 | } | 20 | } |
21 | 21 | ||
diff --git a/arch/ia64/sn/kernel/sn2/timer_interrupt.c b/arch/ia64/sn/kernel/sn2/timer_interrupt.c index cde7375390b0..adf5db2e2afe 100644 --- a/arch/ia64/sn/kernel/sn2/timer_interrupt.c +++ b/arch/ia64/sn/kernel/sn2/timer_interrupt.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * | 2 | * |
3 | * | 3 | * |
4 | * Copyright (c) 2003 Silicon Graphics, Inc. All Rights Reserved. | 4 | * Copyright (c) 2005 Silicon Graphics, Inc. All Rights Reserved. |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify it | 6 | * This program is free software; you can redistribute it and/or modify it |
7 | * under the terms of version 2 of the GNU General Public License | 7 | * under the terms of version 2 of the GNU General Public License |
@@ -50,14 +50,16 @@ void sn_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |||
50 | LED_CPU_HEARTBEAT, LED_CPU_HEARTBEAT); | 50 | LED_CPU_HEARTBEAT, LED_CPU_HEARTBEAT); |
51 | } | 51 | } |
52 | 52 | ||
53 | if (enable_shub_wars_1_1()) { | 53 | if (is_shub1()) { |
54 | /* Bugfix code for SHUB 1.1 */ | 54 | if (enable_shub_wars_1_1()) { |
55 | if (pda->pio_shub_war_cam_addr) | 55 | /* Bugfix code for SHUB 1.1 */ |
56 | *pda->pio_shub_war_cam_addr = 0x8000000000000010UL; | 56 | if (pda->pio_shub_war_cam_addr) |
57 | *pda->pio_shub_war_cam_addr = 0x8000000000000010UL; | ||
58 | } | ||
59 | if (pda->sn_lb_int_war_ticks == 0) | ||
60 | sn_lb_int_war_check(); | ||
61 | pda->sn_lb_int_war_ticks++; | ||
62 | if (pda->sn_lb_int_war_ticks >= SN_LB_INT_WAR_INTERVAL) | ||
63 | pda->sn_lb_int_war_ticks = 0; | ||
57 | } | 64 | } |
58 | if (pda->sn_lb_int_war_ticks == 0) | ||
59 | sn_lb_int_war_check(); | ||
60 | pda->sn_lb_int_war_ticks++; | ||
61 | if (pda->sn_lb_int_war_ticks >= SN_LB_INT_WAR_INTERVAL) | ||
62 | pda->sn_lb_int_war_ticks = 0; | ||
63 | } | 65 | } |