diff options
Diffstat (limited to 'arch/ia64')
46 files changed, 1038 insertions, 529 deletions
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig index a85ea9d37f05..10b6b9e7716b 100644 --- a/arch/ia64/Kconfig +++ b/arch/ia64/Kconfig | |||
@@ -252,6 +252,15 @@ config NR_CPUS | |||
252 | than 64 will cause the use of a CPU mask array, causing a small | 252 | than 64 will cause the use of a CPU mask array, causing a small |
253 | performance hit. | 253 | performance hit. |
254 | 254 | ||
255 | config IA64_NR_NODES | ||
256 | int "Maximum number of NODEs (256-1024)" if (IA64_SGI_SN2 || IA64_GENERIC) | ||
257 | range 256 1024 | ||
258 | depends on IA64_SGI_SN2 || IA64_GENERIC | ||
259 | default "256" | ||
260 | help | ||
261 | This option specifies the maximum number of nodes in your SSI system. | ||
262 | If in doubt, use the default. | ||
263 | |||
255 | config HOTPLUG_CPU | 264 | config HOTPLUG_CPU |
256 | bool "Support for hot-pluggable CPUs (EXPERIMENTAL)" | 265 | bool "Support for hot-pluggable CPUs (EXPERIMENTAL)" |
257 | depends on SMP && EXPERIMENTAL | 266 | depends on SMP && EXPERIMENTAL |
@@ -271,6 +280,25 @@ config SCHED_SMT | |||
271 | Intel IA64 chips with MultiThreading at a cost of slightly increased | 280 | Intel IA64 chips with MultiThreading at a cost of slightly increased |
272 | overhead in some places. If unsure say N here. | 281 | overhead in some places. If unsure say N here. |
273 | 282 | ||
283 | config PERMIT_BSP_REMOVE | ||
284 | bool "Support removal of Bootstrap Processor" | ||
285 | depends on HOTPLUG_CPU | ||
286 | default n | ||
287 | ---help--- | ||
288 | Say Y here if your platform SAL will support removal of BSP with HOTPLUG_CPU | ||
289 | support. | ||
290 | |||
291 | config FORCE_CPEI_RETARGET | ||
292 | bool "Force assumption that CPEI can be re-targetted" | ||
293 | depends on PERMIT_BSP_REMOVE | ||
294 | default n | ||
295 | ---help--- | ||
296 | Say Y if you need to force the assumption that CPEI can be re-targetted to | ||
297 | any cpu in the system. This hint is available via ACPI 3.0 specifications. | ||
298 | Tiger4 systems are capable of re-directing CPEI to any CPU other than BSP. | ||
299 | This option it useful to enable this feature on older BIOS's as well. | ||
300 | You can also enable this by using boot command line option force_cpei=1. | ||
301 | |||
274 | config PREEMPT | 302 | config PREEMPT |
275 | bool "Preemptible Kernel" | 303 | bool "Preemptible Kernel" |
276 | help | 304 | help |
diff --git a/arch/ia64/Makefile b/arch/ia64/Makefile index f722e1a25948..80ea7506fa1a 100644 --- a/arch/ia64/Makefile +++ b/arch/ia64/Makefile | |||
@@ -1,6 +1,9 @@ | |||
1 | # | 1 | # |
2 | # ia64/Makefile | 2 | # ia64/Makefile |
3 | # | 3 | # |
4 | # This file is included by the global makefile so that you can add your own | ||
5 | # architecture-specific flags and dependencies. | ||
6 | # | ||
4 | # This file is subject to the terms and conditions of the GNU General Public | 7 | # This file is subject to the terms and conditions of the GNU General Public |
5 | # License. See the file "COPYING" in the main directory of this archive | 8 | # License. See the file "COPYING" in the main directory of this archive |
6 | # for more details. | 9 | # for more details. |
@@ -62,7 +65,7 @@ drivers-$(CONFIG_OPROFILE) += arch/ia64/oprofile/ | |||
62 | 65 | ||
63 | boot := arch/ia64/hp/sim/boot | 66 | boot := arch/ia64/hp/sim/boot |
64 | 67 | ||
65 | .PHONY: boot compressed check | 68 | PHONY += boot compressed check |
66 | 69 | ||
67 | all: compressed unwcheck | 70 | all: compressed unwcheck |
68 | 71 | ||
diff --git a/arch/ia64/configs/gensparse_defconfig b/arch/ia64/configs/gensparse_defconfig index 744fd2f79f61..0d29aa2066b3 100644 --- a/arch/ia64/configs/gensparse_defconfig +++ b/arch/ia64/configs/gensparse_defconfig | |||
@@ -116,6 +116,7 @@ CONFIG_IOSAPIC=y | |||
116 | CONFIG_FORCE_MAX_ZONEORDER=17 | 116 | CONFIG_FORCE_MAX_ZONEORDER=17 |
117 | CONFIG_SMP=y | 117 | CONFIG_SMP=y |
118 | CONFIG_NR_CPUS=512 | 118 | CONFIG_NR_CPUS=512 |
119 | CONFIG_IA64_NR_NODES=256 | ||
119 | CONFIG_HOTPLUG_CPU=y | 120 | CONFIG_HOTPLUG_CPU=y |
120 | # CONFIG_SCHED_SMT is not set | 121 | # CONFIG_SCHED_SMT is not set |
121 | # CONFIG_PREEMPT is not set | 122 | # CONFIG_PREEMPT is not set |
diff --git a/arch/ia64/configs/sn2_defconfig b/arch/ia64/configs/sn2_defconfig index 8206752161bb..a718034d68d0 100644 --- a/arch/ia64/configs/sn2_defconfig +++ b/arch/ia64/configs/sn2_defconfig | |||
@@ -116,6 +116,7 @@ CONFIG_IA64_SGI_SN_XP=m | |||
116 | CONFIG_FORCE_MAX_ZONEORDER=17 | 116 | CONFIG_FORCE_MAX_ZONEORDER=17 |
117 | CONFIG_SMP=y | 117 | CONFIG_SMP=y |
118 | CONFIG_NR_CPUS=1024 | 118 | CONFIG_NR_CPUS=1024 |
119 | CONFIG_IA64_NR_NODES=256 | ||
119 | # CONFIG_HOTPLUG_CPU is not set | 120 | # CONFIG_HOTPLUG_CPU is not set |
120 | CONFIG_SCHED_SMT=y | 121 | CONFIG_SCHED_SMT=y |
121 | CONFIG_PREEMPT=y | 122 | CONFIG_PREEMPT=y |
diff --git a/arch/ia64/configs/tiger_defconfig b/arch/ia64/configs/tiger_defconfig index 125568118b84..766bf4955432 100644 --- a/arch/ia64/configs/tiger_defconfig +++ b/arch/ia64/configs/tiger_defconfig | |||
@@ -116,6 +116,8 @@ CONFIG_FORCE_MAX_ZONEORDER=17 | |||
116 | CONFIG_SMP=y | 116 | CONFIG_SMP=y |
117 | CONFIG_NR_CPUS=4 | 117 | CONFIG_NR_CPUS=4 |
118 | CONFIG_HOTPLUG_CPU=y | 118 | CONFIG_HOTPLUG_CPU=y |
119 | CONFIG_PERMIT_BSP_REMOVE=y | ||
120 | CONFIG_FORCE_CPEI_RETARGET=y | ||
119 | # CONFIG_SCHED_SMT is not set | 121 | # CONFIG_SCHED_SMT is not set |
120 | # CONFIG_PREEMPT is not set | 122 | # CONFIG_PREEMPT is not set |
121 | CONFIG_SELECT_MEMORY_MODEL=y | 123 | CONFIG_SELECT_MEMORY_MODEL=y |
diff --git a/arch/ia64/defconfig b/arch/ia64/defconfig index 3e767288a745..6cba55da572a 100644 --- a/arch/ia64/defconfig +++ b/arch/ia64/defconfig | |||
@@ -116,6 +116,7 @@ CONFIG_IOSAPIC=y | |||
116 | CONFIG_FORCE_MAX_ZONEORDER=17 | 116 | CONFIG_FORCE_MAX_ZONEORDER=17 |
117 | CONFIG_SMP=y | 117 | CONFIG_SMP=y |
118 | CONFIG_NR_CPUS=512 | 118 | CONFIG_NR_CPUS=512 |
119 | CONFIG_IA64_NR_NODES=256 | ||
119 | CONFIG_HOTPLUG_CPU=y | 120 | CONFIG_HOTPLUG_CPU=y |
120 | # CONFIG_SCHED_SMT is not set | 121 | # CONFIG_SCHED_SMT is not set |
121 | # CONFIG_PREEMPT is not set | 122 | # CONFIG_PREEMPT is not set |
diff --git a/arch/ia64/dig/setup.c b/arch/ia64/dig/setup.c index c9104bfff667..38aa9c108857 100644 --- a/arch/ia64/dig/setup.c +++ b/arch/ia64/dig/setup.c | |||
@@ -69,8 +69,3 @@ dig_setup (char **cmdline_p) | |||
69 | screen_info.orig_video_isVGA = 1; /* XXX fake */ | 69 | screen_info.orig_video_isVGA = 1; /* XXX fake */ |
70 | screen_info.orig_video_ega_bx = 3; /* XXX fake */ | 70 | screen_info.orig_video_ega_bx = 3; /* XXX fake */ |
71 | } | 71 | } |
72 | |||
73 | void __init | ||
74 | dig_irq_init (void) | ||
75 | { | ||
76 | } | ||
diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index 626cdc83668b..0e5c6ae50228 100644 --- a/arch/ia64/hp/sim/simserial.c +++ b/arch/ia64/hp/sim/simserial.c | |||
@@ -46,11 +46,6 @@ | |||
46 | #define KEYBOARD_INTR 3 /* must match with simulator! */ | 46 | #define KEYBOARD_INTR 3 /* must match with simulator! */ |
47 | 47 | ||
48 | #define NR_PORTS 1 /* only one port for now */ | 48 | #define NR_PORTS 1 /* only one port for now */ |
49 | #define SERIAL_INLINE 1 | ||
50 | |||
51 | #ifdef SERIAL_INLINE | ||
52 | #define _INLINE_ inline | ||
53 | #endif | ||
54 | 49 | ||
55 | #define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT) | 50 | #define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT) |
56 | 51 | ||
@@ -237,7 +232,7 @@ static void rs_put_char(struct tty_struct *tty, unsigned char ch) | |||
237 | local_irq_restore(flags); | 232 | local_irq_restore(flags); |
238 | } | 233 | } |
239 | 234 | ||
240 | static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done) | 235 | static void transmit_chars(struct async_struct *info, int *intr_done) |
241 | { | 236 | { |
242 | int count; | 237 | int count; |
243 | unsigned long flags; | 238 | unsigned long flags; |
diff --git a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c index 70dba1f0e2ee..13e739e4c84d 100644 --- a/arch/ia64/ia32/sys_ia32.c +++ b/arch/ia64/ia32/sys_ia32.c | |||
@@ -1166,19 +1166,7 @@ put_tv32 (struct compat_timeval __user *o, struct timeval *i) | |||
1166 | asmlinkage unsigned long | 1166 | asmlinkage unsigned long |
1167 | sys32_alarm (unsigned int seconds) | 1167 | sys32_alarm (unsigned int seconds) |
1168 | { | 1168 | { |
1169 | struct itimerval it_new, it_old; | 1169 | return alarm_setitimer(seconds); |
1170 | unsigned int oldalarm; | ||
1171 | |||
1172 | it_new.it_interval.tv_sec = it_new.it_interval.tv_usec = 0; | ||
1173 | it_new.it_value.tv_sec = seconds; | ||
1174 | it_new.it_value.tv_usec = 0; | ||
1175 | do_setitimer(ITIMER_REAL, &it_new, &it_old); | ||
1176 | oldalarm = it_old.it_value.tv_sec; | ||
1177 | /* ehhh.. We can't return 0 if we have an alarm pending.. */ | ||
1178 | /* And we'd better return too much than too little anyway */ | ||
1179 | if (it_old.it_value.tv_usec) | ||
1180 | oldalarm++; | ||
1181 | return oldalarm; | ||
1182 | } | 1170 | } |
1183 | 1171 | ||
1184 | /* Translations due to time_t size differences. Which affects all | 1172 | /* Translations due to time_t size differences. Which affects all |
diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c index ecd44bdc8394..a4e218ce2edb 100644 --- a/arch/ia64/kernel/acpi.c +++ b/arch/ia64/kernel/acpi.c | |||
@@ -284,19 +284,24 @@ acpi_parse_plat_int_src(acpi_table_entry_header * header, | |||
284 | return 0; | 284 | return 0; |
285 | } | 285 | } |
286 | 286 | ||
287 | #ifdef CONFIG_HOTPLUG_CPU | ||
287 | unsigned int can_cpei_retarget(void) | 288 | unsigned int can_cpei_retarget(void) |
288 | { | 289 | { |
289 | extern int cpe_vector; | 290 | extern int cpe_vector; |
291 | extern unsigned int force_cpei_retarget; | ||
290 | 292 | ||
291 | /* | 293 | /* |
292 | * Only if CPEI is supported and the override flag | 294 | * Only if CPEI is supported and the override flag |
293 | * is present, otherwise return that its re-targettable | 295 | * is present, otherwise return that its re-targettable |
294 | * if we are in polling mode. | 296 | * if we are in polling mode. |
295 | */ | 297 | */ |
296 | if (cpe_vector > 0 && !acpi_cpei_override) | 298 | if (cpe_vector > 0) { |
297 | return 0; | 299 | if (acpi_cpei_override || force_cpei_retarget) |
298 | else | 300 | return 1; |
299 | return 1; | 301 | else |
302 | return 0; | ||
303 | } | ||
304 | return 1; | ||
300 | } | 305 | } |
301 | 306 | ||
302 | unsigned int is_cpu_cpei_target(unsigned int cpu) | 307 | unsigned int is_cpu_cpei_target(unsigned int cpu) |
@@ -315,6 +320,7 @@ void set_cpei_target_cpu(unsigned int cpu) | |||
315 | { | 320 | { |
316 | acpi_cpei_phys_cpuid = cpu_physical_id(cpu); | 321 | acpi_cpei_phys_cpuid = cpu_physical_id(cpu); |
317 | } | 322 | } |
323 | #endif | ||
318 | 324 | ||
319 | unsigned int get_cpei_target_cpu(void) | 325 | unsigned int get_cpei_target_cpu(void) |
320 | { | 326 | { |
@@ -414,6 +420,26 @@ int __devinitdata pxm_to_nid_map[MAX_PXM_DOMAINS]; | |||
414 | int __initdata nid_to_pxm_map[MAX_NUMNODES]; | 420 | int __initdata nid_to_pxm_map[MAX_NUMNODES]; |
415 | static struct acpi_table_slit __initdata *slit_table; | 421 | static struct acpi_table_slit __initdata *slit_table; |
416 | 422 | ||
423 | static int get_processor_proximity_domain(struct acpi_table_processor_affinity *pa) | ||
424 | { | ||
425 | int pxm; | ||
426 | |||
427 | pxm = pa->proximity_domain; | ||
428 | if (ia64_platform_is("sn2")) | ||
429 | pxm += pa->reserved[0] << 8; | ||
430 | return pxm; | ||
431 | } | ||
432 | |||
433 | static int get_memory_proximity_domain(struct acpi_table_memory_affinity *ma) | ||
434 | { | ||
435 | int pxm; | ||
436 | |||
437 | pxm = ma->proximity_domain; | ||
438 | if (ia64_platform_is("sn2")) | ||
439 | pxm += ma->reserved1[0] << 8; | ||
440 | return pxm; | ||
441 | } | ||
442 | |||
417 | /* | 443 | /* |
418 | * ACPI 2.0 SLIT (System Locality Information Table) | 444 | * ACPI 2.0 SLIT (System Locality Information Table) |
419 | * http://devresource.hp.com/devresource/Docs/TechPapers/IA64/slit.pdf | 445 | * http://devresource.hp.com/devresource/Docs/TechPapers/IA64/slit.pdf |
@@ -437,13 +463,20 @@ void __init acpi_numa_slit_init(struct acpi_table_slit *slit) | |||
437 | void __init | 463 | void __init |
438 | acpi_numa_processor_affinity_init(struct acpi_table_processor_affinity *pa) | 464 | acpi_numa_processor_affinity_init(struct acpi_table_processor_affinity *pa) |
439 | { | 465 | { |
466 | int pxm; | ||
467 | |||
468 | if (!pa->flags.enabled) | ||
469 | return; | ||
470 | |||
471 | pxm = get_processor_proximity_domain(pa); | ||
472 | |||
440 | /* record this node in proximity bitmap */ | 473 | /* record this node in proximity bitmap */ |
441 | pxm_bit_set(pa->proximity_domain); | 474 | pxm_bit_set(pxm); |
442 | 475 | ||
443 | node_cpuid[srat_num_cpus].phys_id = | 476 | node_cpuid[srat_num_cpus].phys_id = |
444 | (pa->apic_id << 8) | (pa->lsapic_eid); | 477 | (pa->apic_id << 8) | (pa->lsapic_eid); |
445 | /* nid should be overridden as logical node id later */ | 478 | /* nid should be overridden as logical node id later */ |
446 | node_cpuid[srat_num_cpus].nid = pa->proximity_domain; | 479 | node_cpuid[srat_num_cpus].nid = pxm; |
447 | srat_num_cpus++; | 480 | srat_num_cpus++; |
448 | } | 481 | } |
449 | 482 | ||
@@ -451,10 +484,10 @@ void __init | |||
451 | acpi_numa_memory_affinity_init(struct acpi_table_memory_affinity *ma) | 484 | acpi_numa_memory_affinity_init(struct acpi_table_memory_affinity *ma) |
452 | { | 485 | { |
453 | unsigned long paddr, size; | 486 | unsigned long paddr, size; |
454 | u8 pxm; | 487 | int pxm; |
455 | struct node_memblk_s *p, *q, *pend; | 488 | struct node_memblk_s *p, *q, *pend; |
456 | 489 | ||
457 | pxm = ma->proximity_domain; | 490 | pxm = get_memory_proximity_domain(ma); |
458 | 491 | ||
459 | /* fill node memory chunk structure */ | 492 | /* fill node memory chunk structure */ |
460 | paddr = ma->base_addr_hi; | 493 | paddr = ma->base_addr_hi; |
diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S index 930fdfca6ddb..0e3eda99e549 100644 --- a/arch/ia64/kernel/entry.S +++ b/arch/ia64/kernel/entry.S | |||
@@ -1102,9 +1102,6 @@ skip_rbs_switch: | |||
1102 | st8 [r2]=r8 | 1102 | st8 [r2]=r8 |
1103 | st8 [r3]=r10 | 1103 | st8 [r3]=r10 |
1104 | .work_pending: | 1104 | .work_pending: |
1105 | tbit.nz p6,p0=r31,TIF_SIGDELAYED // signal delayed from MCA/INIT/NMI/PMI context? | ||
1106 | (p6) br.cond.sptk.few .sigdelayed | ||
1107 | ;; | ||
1108 | tbit.z p6,p0=r31,TIF_NEED_RESCHED // current_thread_info()->need_resched==0? | 1105 | tbit.z p6,p0=r31,TIF_NEED_RESCHED // current_thread_info()->need_resched==0? |
1109 | (p6) br.cond.sptk.few .notify | 1106 | (p6) br.cond.sptk.few .notify |
1110 | #ifdef CONFIG_PREEMPT | 1107 | #ifdef CONFIG_PREEMPT |
@@ -1131,17 +1128,6 @@ skip_rbs_switch: | |||
1131 | (pLvSys)br.cond.sptk.few .work_pending_syscall_end | 1128 | (pLvSys)br.cond.sptk.few .work_pending_syscall_end |
1132 | br.cond.sptk.many .work_processed_kernel // don't re-check | 1129 | br.cond.sptk.many .work_processed_kernel // don't re-check |
1133 | 1130 | ||
1134 | // There is a delayed signal that was detected in MCA/INIT/NMI/PMI context where | ||
1135 | // it could not be delivered. Deliver it now. The signal might be for us and | ||
1136 | // may set TIF_SIGPENDING, so redrive ia64_leave_* after processing the delayed | ||
1137 | // signal. | ||
1138 | |||
1139 | .sigdelayed: | ||
1140 | br.call.sptk.many rp=do_sigdelayed | ||
1141 | cmp.eq p6,p0=r0,r0 // p6 <- 1, always re-check | ||
1142 | (pLvSys)br.cond.sptk.few .work_pending_syscall_end | ||
1143 | br.cond.sptk.many .work_processed_kernel // re-check | ||
1144 | |||
1145 | .work_pending_syscall_end: | 1131 | .work_pending_syscall_end: |
1146 | adds r2=PT(R8)+16,r12 | 1132 | adds r2=PT(R8)+16,r12 |
1147 | adds r3=PT(R10)+16,r12 | 1133 | adds r3=PT(R10)+16,r12 |
diff --git a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c index 574084f343fa..8832c553230a 100644 --- a/arch/ia64/kernel/iosapic.c +++ b/arch/ia64/kernel/iosapic.c | |||
@@ -631,6 +631,7 @@ get_target_cpu (unsigned int gsi, int vector) | |||
631 | { | 631 | { |
632 | #ifdef CONFIG_SMP | 632 | #ifdef CONFIG_SMP |
633 | static int cpu = -1; | 633 | static int cpu = -1; |
634 | extern int cpe_vector; | ||
634 | 635 | ||
635 | /* | 636 | /* |
636 | * In case of vector shared by multiple RTEs, all RTEs that | 637 | * In case of vector shared by multiple RTEs, all RTEs that |
@@ -653,6 +654,11 @@ get_target_cpu (unsigned int gsi, int vector) | |||
653 | if (!cpu_online(smp_processor_id())) | 654 | if (!cpu_online(smp_processor_id())) |
654 | return cpu_physical_id(smp_processor_id()); | 655 | return cpu_physical_id(smp_processor_id()); |
655 | 656 | ||
657 | #ifdef CONFIG_ACPI | ||
658 | if (cpe_vector > 0 && vector == IA64_CPEP_VECTOR) | ||
659 | return get_cpei_target_cpu(); | ||
660 | #endif | ||
661 | |||
656 | #ifdef CONFIG_NUMA | 662 | #ifdef CONFIG_NUMA |
657 | { | 663 | { |
658 | int num_cpus, cpu_index, iosapic_index, numa_cpu, i = 0; | 664 | int num_cpus, cpu_index, iosapic_index, numa_cpu, i = 0; |
diff --git a/arch/ia64/kernel/irq.c b/arch/ia64/kernel/irq.c index d33244c32759..5ce908ef9c95 100644 --- a/arch/ia64/kernel/irq.c +++ b/arch/ia64/kernel/irq.c | |||
@@ -163,8 +163,19 @@ void fixup_irqs(void) | |||
163 | { | 163 | { |
164 | unsigned int irq; | 164 | unsigned int irq; |
165 | extern void ia64_process_pending_intr(void); | 165 | extern void ia64_process_pending_intr(void); |
166 | extern void ia64_disable_timer(void); | ||
167 | extern volatile int time_keeper_id; | ||
168 | |||
169 | ia64_disable_timer(); | ||
170 | |||
171 | /* | ||
172 | * Find a new timesync master | ||
173 | */ | ||
174 | if (smp_processor_id() == time_keeper_id) { | ||
175 | time_keeper_id = first_cpu(cpu_online_map); | ||
176 | printk ("CPU %d is now promoted to time-keeper master\n", time_keeper_id); | ||
177 | } | ||
166 | 178 | ||
167 | ia64_set_itv(1<<16); | ||
168 | /* | 179 | /* |
169 | * Phase 1: Locate irq's bound to this cpu and | 180 | * Phase 1: Locate irq's bound to this cpu and |
170 | * relocate them for cpu removal. | 181 | * relocate them for cpu removal. |
diff --git a/arch/ia64/kernel/ivt.S b/arch/ia64/kernel/ivt.S index dcd906fe5749..829a43cab797 100644 --- a/arch/ia64/kernel/ivt.S +++ b/arch/ia64/kernel/ivt.S | |||
@@ -865,6 +865,7 @@ ENTRY(interrupt) | |||
865 | ;; | 865 | ;; |
866 | SAVE_REST | 866 | SAVE_REST |
867 | ;; | 867 | ;; |
868 | MCA_RECOVER_RANGE(interrupt) | ||
868 | alloc r14=ar.pfs,0,0,2,0 // must be first in an insn group | 869 | alloc r14=ar.pfs,0,0,2,0 // must be first in an insn group |
869 | mov out0=cr.ivr // pass cr.ivr as first arg | 870 | mov out0=cr.ivr // pass cr.ivr as first arg |
870 | add out1=16,sp // pass pointer to pt_regs as second arg | 871 | add out1=16,sp // pass pointer to pt_regs as second arg |
diff --git a/arch/ia64/kernel/machvec.c b/arch/ia64/kernel/machvec.c index c3a04ee7f4f6..4b0b71d5aef4 100644 --- a/arch/ia64/kernel/machvec.c +++ b/arch/ia64/kernel/machvec.c | |||
@@ -14,7 +14,15 @@ | |||
14 | struct ia64_machine_vector ia64_mv; | 14 | struct ia64_machine_vector ia64_mv; |
15 | EXPORT_SYMBOL(ia64_mv); | 15 | EXPORT_SYMBOL(ia64_mv); |
16 | 16 | ||
17 | static struct ia64_machine_vector * | 17 | static __initdata const char *mvec_name; |
18 | static __init int setup_mvec(char *s) | ||
19 | { | ||
20 | mvec_name = s; | ||
21 | return 0; | ||
22 | } | ||
23 | early_param("machvec", setup_mvec); | ||
24 | |||
25 | static struct ia64_machine_vector * __init | ||
18 | lookup_machvec (const char *name) | 26 | lookup_machvec (const char *name) |
19 | { | 27 | { |
20 | extern struct ia64_machine_vector machvec_start[]; | 28 | extern struct ia64_machine_vector machvec_start[]; |
@@ -33,10 +41,13 @@ machvec_init (const char *name) | |||
33 | { | 41 | { |
34 | struct ia64_machine_vector *mv; | 42 | struct ia64_machine_vector *mv; |
35 | 43 | ||
44 | if (!name) | ||
45 | name = mvec_name ? mvec_name : acpi_get_sysname(); | ||
36 | mv = lookup_machvec(name); | 46 | mv = lookup_machvec(name); |
37 | if (!mv) { | 47 | if (!mv) |
38 | panic("generic kernel failed to find machine vector for platform %s!", name); | 48 | panic("generic kernel failed to find machine vector for" |
39 | } | 49 | " platform %s!", name); |
50 | |||
40 | ia64_mv = *mv; | 51 | ia64_mv = *mv; |
41 | printk(KERN_INFO "booting generic kernel on platform %s\n", name); | 52 | printk(KERN_INFO "booting generic kernel on platform %s\n", name); |
42 | } | 53 | } |
diff --git a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c index ee7eec9ee576..87ff7fe33cfb 100644 --- a/arch/ia64/kernel/mca.c +++ b/arch/ia64/kernel/mca.c | |||
@@ -83,6 +83,7 @@ | |||
83 | #include <asm/irq.h> | 83 | #include <asm/irq.h> |
84 | #include <asm/hw_irq.h> | 84 | #include <asm/hw_irq.h> |
85 | 85 | ||
86 | #include "mca_drv.h" | ||
86 | #include "entry.h" | 87 | #include "entry.h" |
87 | 88 | ||
88 | #if defined(IA64_MCA_DEBUG_INFO) | 89 | #if defined(IA64_MCA_DEBUG_INFO) |
@@ -133,7 +134,7 @@ static int cpe_poll_enabled = 1; | |||
133 | 134 | ||
134 | extern void salinfo_log_wakeup(int type, u8 *buffer, u64 size, int irqsafe); | 135 | extern void salinfo_log_wakeup(int type, u8 *buffer, u64 size, int irqsafe); |
135 | 136 | ||
136 | static int mca_init; | 137 | static int mca_init __initdata; |
137 | 138 | ||
138 | 139 | ||
139 | static void inline | 140 | static void inline |
@@ -184,7 +185,7 @@ static ia64_state_log_t ia64_state_log[IA64_MAX_LOG_TYPES]; | |||
184 | * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC,CPE}) | 185 | * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC,CPE}) |
185 | * Outputs : None | 186 | * Outputs : None |
186 | */ | 187 | */ |
187 | static void | 188 | static void __init |
188 | ia64_log_init(int sal_info_type) | 189 | ia64_log_init(int sal_info_type) |
189 | { | 190 | { |
190 | u64 max_size = 0; | 191 | u64 max_size = 0; |
@@ -282,13 +283,53 @@ ia64_mca_log_sal_error_record(int sal_info_type) | |||
282 | } | 283 | } |
283 | 284 | ||
284 | /* | 285 | /* |
285 | * platform dependent error handling | 286 | * search_mca_table |
287 | * See if the MCA surfaced in an instruction range | ||
288 | * that has been tagged as recoverable. | ||
289 | * | ||
290 | * Inputs | ||
291 | * first First address range to check | ||
292 | * last Last address range to check | ||
293 | * ip Instruction pointer, address we are looking for | ||
294 | * | ||
295 | * Return value: | ||
296 | * 1 on Success (in the table)/ 0 on Failure (not in the table) | ||
286 | */ | 297 | */ |
287 | #ifndef PLATFORM_MCA_HANDLERS | 298 | int |
299 | search_mca_table (const struct mca_table_entry *first, | ||
300 | const struct mca_table_entry *last, | ||
301 | unsigned long ip) | ||
302 | { | ||
303 | const struct mca_table_entry *curr; | ||
304 | u64 curr_start, curr_end; | ||
305 | |||
306 | curr = first; | ||
307 | while (curr <= last) { | ||
308 | curr_start = (u64) &curr->start_addr + curr->start_addr; | ||
309 | curr_end = (u64) &curr->end_addr + curr->end_addr; | ||
310 | |||
311 | if ((ip >= curr_start) && (ip <= curr_end)) { | ||
312 | return 1; | ||
313 | } | ||
314 | curr++; | ||
315 | } | ||
316 | return 0; | ||
317 | } | ||
318 | |||
319 | /* Given an address, look for it in the mca tables. */ | ||
320 | int mca_recover_range(unsigned long addr) | ||
321 | { | ||
322 | extern struct mca_table_entry __start___mca_table[]; | ||
323 | extern struct mca_table_entry __stop___mca_table[]; | ||
324 | |||
325 | return search_mca_table(__start___mca_table, __stop___mca_table-1, addr); | ||
326 | } | ||
327 | EXPORT_SYMBOL_GPL(mca_recover_range); | ||
288 | 328 | ||
289 | #ifdef CONFIG_ACPI | 329 | #ifdef CONFIG_ACPI |
290 | 330 | ||
291 | int cpe_vector = -1; | 331 | int cpe_vector = -1; |
332 | int ia64_cpe_irq = -1; | ||
292 | 333 | ||
293 | static irqreturn_t | 334 | static irqreturn_t |
294 | ia64_mca_cpe_int_handler (int cpe_irq, void *arg, struct pt_regs *ptregs) | 335 | ia64_mca_cpe_int_handler (int cpe_irq, void *arg, struct pt_regs *ptregs) |
@@ -359,7 +400,7 @@ ia64_mca_cpe_int_handler (int cpe_irq, void *arg, struct pt_regs *ptregs) | |||
359 | * Outputs | 400 | * Outputs |
360 | * None | 401 | * None |
361 | */ | 402 | */ |
362 | static void | 403 | static void __init |
363 | ia64_mca_register_cpev (int cpev) | 404 | ia64_mca_register_cpev (int cpev) |
364 | { | 405 | { |
365 | /* Register the CPE interrupt vector with SAL */ | 406 | /* Register the CPE interrupt vector with SAL */ |
@@ -377,8 +418,6 @@ ia64_mca_register_cpev (int cpev) | |||
377 | } | 418 | } |
378 | #endif /* CONFIG_ACPI */ | 419 | #endif /* CONFIG_ACPI */ |
379 | 420 | ||
380 | #endif /* PLATFORM_MCA_HANDLERS */ | ||
381 | |||
382 | /* | 421 | /* |
383 | * ia64_mca_cmc_vector_setup | 422 | * ia64_mca_cmc_vector_setup |
384 | * | 423 | * |
@@ -392,7 +431,7 @@ ia64_mca_register_cpev (int cpev) | |||
392 | * Outputs | 431 | * Outputs |
393 | * None | 432 | * None |
394 | */ | 433 | */ |
395 | void | 434 | void __cpuinit |
396 | ia64_mca_cmc_vector_setup (void) | 435 | ia64_mca_cmc_vector_setup (void) |
397 | { | 436 | { |
398 | cmcv_reg_t cmcv; | 437 | cmcv_reg_t cmcv; |
@@ -630,6 +669,32 @@ copy_reg(const u64 *fr, u64 fnat, u64 *tr, u64 *tnat) | |||
630 | *tnat |= (nat << tslot); | 669 | *tnat |= (nat << tslot); |
631 | } | 670 | } |
632 | 671 | ||
672 | /* Change the comm field on the MCA/INT task to include the pid that | ||
673 | * was interrupted, it makes for easier debugging. If that pid was 0 | ||
674 | * (swapper or nested MCA/INIT) then use the start of the previous comm | ||
675 | * field suffixed with its cpu. | ||
676 | */ | ||
677 | |||
678 | static void | ||
679 | ia64_mca_modify_comm(const task_t *previous_current) | ||
680 | { | ||
681 | char *p, comm[sizeof(current->comm)]; | ||
682 | if (previous_current->pid) | ||
683 | snprintf(comm, sizeof(comm), "%s %d", | ||
684 | current->comm, previous_current->pid); | ||
685 | else { | ||
686 | int l; | ||
687 | if ((p = strchr(previous_current->comm, ' '))) | ||
688 | l = p - previous_current->comm; | ||
689 | else | ||
690 | l = strlen(previous_current->comm); | ||
691 | snprintf(comm, sizeof(comm), "%s %*s %d", | ||
692 | current->comm, l, previous_current->comm, | ||
693 | task_thread_info(previous_current)->cpu); | ||
694 | } | ||
695 | memcpy(current->comm, comm, sizeof(current->comm)); | ||
696 | } | ||
697 | |||
633 | /* On entry to this routine, we are running on the per cpu stack, see | 698 | /* On entry to this routine, we are running on the per cpu stack, see |
634 | * mca_asm.h. The original stack has not been touched by this event. Some of | 699 | * mca_asm.h. The original stack has not been touched by this event. Some of |
635 | * the original stack's registers will be in the RBS on this stack. This stack | 700 | * the original stack's registers will be in the RBS on this stack. This stack |
@@ -648,7 +713,7 @@ ia64_mca_modify_original_stack(struct pt_regs *regs, | |||
648 | struct ia64_sal_os_state *sos, | 713 | struct ia64_sal_os_state *sos, |
649 | const char *type) | 714 | const char *type) |
650 | { | 715 | { |
651 | char *p, comm[sizeof(current->comm)]; | 716 | char *p; |
652 | ia64_va va; | 717 | ia64_va va; |
653 | extern char ia64_leave_kernel[]; /* Need asm address, not function descriptor */ | 718 | extern char ia64_leave_kernel[]; /* Need asm address, not function descriptor */ |
654 | const pal_min_state_area_t *ms = sos->pal_min_state; | 719 | const pal_min_state_area_t *ms = sos->pal_min_state; |
@@ -721,54 +786,43 @@ ia64_mca_modify_original_stack(struct pt_regs *regs, | |||
721 | /* Verify the previous stack state before we change it */ | 786 | /* Verify the previous stack state before we change it */ |
722 | if (user_mode(regs)) { | 787 | if (user_mode(regs)) { |
723 | msg = "occurred in user space"; | 788 | msg = "occurred in user space"; |
724 | goto no_mod; | 789 | /* previous_current is guaranteed to be valid when the task was |
725 | } | 790 | * in user space, so ... |
726 | if (r13 != sos->prev_IA64_KR_CURRENT) { | 791 | */ |
727 | msg = "inconsistent previous current and r13"; | 792 | ia64_mca_modify_comm(previous_current); |
728 | goto no_mod; | ||
729 | } | ||
730 | if ((r12 - r13) >= KERNEL_STACK_SIZE) { | ||
731 | msg = "inconsistent r12 and r13"; | ||
732 | goto no_mod; | ||
733 | } | ||
734 | if ((ar_bspstore - r13) >= KERNEL_STACK_SIZE) { | ||
735 | msg = "inconsistent ar.bspstore and r13"; | ||
736 | goto no_mod; | ||
737 | } | ||
738 | va.p = old_bspstore; | ||
739 | if (va.f.reg < 5) { | ||
740 | msg = "old_bspstore is in the wrong region"; | ||
741 | goto no_mod; | ||
742 | } | ||
743 | if ((ar_bsp - r13) >= KERNEL_STACK_SIZE) { | ||
744 | msg = "inconsistent ar.bsp and r13"; | ||
745 | goto no_mod; | ||
746 | } | ||
747 | size += (ia64_rse_skip_regs(old_bspstore, slots) - old_bspstore) * 8; | ||
748 | if (ar_bspstore + size > r12) { | ||
749 | msg = "no room for blocked state"; | ||
750 | goto no_mod; | 793 | goto no_mod; |
751 | } | 794 | } |
752 | 795 | ||
753 | /* Change the comm field on the MCA/INT task to include the pid that | 796 | if (!mca_recover_range(ms->pmsa_iip)) { |
754 | * was interrupted, it makes for easier debugging. If that pid was 0 | 797 | if (r13 != sos->prev_IA64_KR_CURRENT) { |
755 | * (swapper or nested MCA/INIT) then use the start of the previous comm | 798 | msg = "inconsistent previous current and r13"; |
756 | * field suffixed with its cpu. | 799 | goto no_mod; |
757 | */ | 800 | } |
758 | if (previous_current->pid) | 801 | if ((r12 - r13) >= KERNEL_STACK_SIZE) { |
759 | snprintf(comm, sizeof(comm), "%s %d", | 802 | msg = "inconsistent r12 and r13"; |
760 | current->comm, previous_current->pid); | 803 | goto no_mod; |
761 | else { | 804 | } |
762 | int l; | 805 | if ((ar_bspstore - r13) >= KERNEL_STACK_SIZE) { |
763 | if ((p = strchr(previous_current->comm, ' '))) | 806 | msg = "inconsistent ar.bspstore and r13"; |
764 | l = p - previous_current->comm; | 807 | goto no_mod; |
765 | else | 808 | } |
766 | l = strlen(previous_current->comm); | 809 | va.p = old_bspstore; |
767 | snprintf(comm, sizeof(comm), "%s %*s %d", | 810 | if (va.f.reg < 5) { |
768 | current->comm, l, previous_current->comm, | 811 | msg = "old_bspstore is in the wrong region"; |
769 | task_thread_info(previous_current)->cpu); | 812 | goto no_mod; |
813 | } | ||
814 | if ((ar_bsp - r13) >= KERNEL_STACK_SIZE) { | ||
815 | msg = "inconsistent ar.bsp and r13"; | ||
816 | goto no_mod; | ||
817 | } | ||
818 | size += (ia64_rse_skip_regs(old_bspstore, slots) - old_bspstore) * 8; | ||
819 | if (ar_bspstore + size > r12) { | ||
820 | msg = "no room for blocked state"; | ||
821 | goto no_mod; | ||
822 | } | ||
770 | } | 823 | } |
771 | memcpy(current->comm, comm, sizeof(current->comm)); | 824 | |
825 | ia64_mca_modify_comm(previous_current); | ||
772 | 826 | ||
773 | /* Make the original task look blocked. First stack a struct pt_regs, | 827 | /* Make the original task look blocked. First stack a struct pt_regs, |
774 | * describing the state at the time of interrupt. mca_asm.S built a | 828 | * describing the state at the time of interrupt. mca_asm.S built a |
@@ -908,7 +962,7 @@ no_mod: | |||
908 | static void | 962 | static void |
909 | ia64_wait_for_slaves(int monarch) | 963 | ia64_wait_for_slaves(int monarch) |
910 | { | 964 | { |
911 | int c, wait = 0; | 965 | int c, wait = 0, missing = 0; |
912 | for_each_online_cpu(c) { | 966 | for_each_online_cpu(c) { |
913 | if (c == monarch) | 967 | if (c == monarch) |
914 | continue; | 968 | continue; |
@@ -919,15 +973,32 @@ ia64_wait_for_slaves(int monarch) | |||
919 | } | 973 | } |
920 | } | 974 | } |
921 | if (!wait) | 975 | if (!wait) |
922 | return; | 976 | goto all_in; |
923 | for_each_online_cpu(c) { | 977 | for_each_online_cpu(c) { |
924 | if (c == monarch) | 978 | if (c == monarch) |
925 | continue; | 979 | continue; |
926 | if (ia64_mc_info.imi_rendez_checkin[c] == IA64_MCA_RENDEZ_CHECKIN_NOTDONE) { | 980 | if (ia64_mc_info.imi_rendez_checkin[c] == IA64_MCA_RENDEZ_CHECKIN_NOTDONE) { |
927 | udelay(5*1000000); /* wait 5 seconds for slaves (arbitrary) */ | 981 | udelay(5*1000000); /* wait 5 seconds for slaves (arbitrary) */ |
982 | if (ia64_mc_info.imi_rendez_checkin[c] == IA64_MCA_RENDEZ_CHECKIN_NOTDONE) | ||
983 | missing = 1; | ||
928 | break; | 984 | break; |
929 | } | 985 | } |
930 | } | 986 | } |
987 | if (!missing) | ||
988 | goto all_in; | ||
989 | printk(KERN_INFO "OS MCA slave did not rendezvous on cpu"); | ||
990 | for_each_online_cpu(c) { | ||
991 | if (c == monarch) | ||
992 | continue; | ||
993 | if (ia64_mc_info.imi_rendez_checkin[c] == IA64_MCA_RENDEZ_CHECKIN_NOTDONE) | ||
994 | printk(" %d", c); | ||
995 | } | ||
996 | printk("\n"); | ||
997 | return; | ||
998 | |||
999 | all_in: | ||
1000 | printk(KERN_INFO "All OS MCA slaves have reached rendezvous\n"); | ||
1001 | return; | ||
931 | } | 1002 | } |
932 | 1003 | ||
933 | /* | 1004 | /* |
@@ -953,6 +1024,10 @@ ia64_mca_handler(struct pt_regs *regs, struct switch_stack *sw, | |||
953 | task_t *previous_current; | 1024 | task_t *previous_current; |
954 | 1025 | ||
955 | oops_in_progress = 1; /* FIXME: make printk NMI/MCA/INIT safe */ | 1026 | oops_in_progress = 1; /* FIXME: make printk NMI/MCA/INIT safe */ |
1027 | console_loglevel = 15; /* make sure printks make it to console */ | ||
1028 | printk(KERN_INFO "Entered OS MCA handler. PSP=%lx cpu=%d monarch=%ld\n", | ||
1029 | sos->proc_state_param, cpu, sos->monarch); | ||
1030 | |||
956 | previous_current = ia64_mca_modify_original_stack(regs, sw, sos, "MCA"); | 1031 | previous_current = ia64_mca_modify_original_stack(regs, sw, sos, "MCA"); |
957 | monarch_cpu = cpu; | 1032 | monarch_cpu = cpu; |
958 | if (notify_die(DIE_MCA_MONARCH_ENTER, "MCA", regs, 0, 0, 0) | 1033 | if (notify_die(DIE_MCA_MONARCH_ENTER, "MCA", regs, 0, 0, 0) |
@@ -1416,7 +1491,7 @@ static struct irqaction mca_cpep_irqaction = { | |||
1416 | * format most of the fields. | 1491 | * format most of the fields. |
1417 | */ | 1492 | */ |
1418 | 1493 | ||
1419 | static void | 1494 | static void __cpuinit |
1420 | format_mca_init_stack(void *mca_data, unsigned long offset, | 1495 | format_mca_init_stack(void *mca_data, unsigned long offset, |
1421 | const char *type, int cpu) | 1496 | const char *type, int cpu) |
1422 | { | 1497 | { |
@@ -1440,15 +1515,17 @@ format_mca_init_stack(void *mca_data, unsigned long offset, | |||
1440 | 1515 | ||
1441 | /* Do per-CPU MCA-related initialization. */ | 1516 | /* Do per-CPU MCA-related initialization. */ |
1442 | 1517 | ||
1443 | void __devinit | 1518 | void __cpuinit |
1444 | ia64_mca_cpu_init(void *cpu_data) | 1519 | ia64_mca_cpu_init(void *cpu_data) |
1445 | { | 1520 | { |
1446 | void *pal_vaddr; | 1521 | void *pal_vaddr; |
1522 | static int first_time = 1; | ||
1447 | 1523 | ||
1448 | if (smp_processor_id() == 0) { | 1524 | if (first_time) { |
1449 | void *mca_data; | 1525 | void *mca_data; |
1450 | int cpu; | 1526 | int cpu; |
1451 | 1527 | ||
1528 | first_time = 0; | ||
1452 | mca_data = alloc_bootmem(sizeof(struct ia64_mca_cpu) | 1529 | mca_data = alloc_bootmem(sizeof(struct ia64_mca_cpu) |
1453 | * NR_CPUS + KERNEL_STACK_SIZE); | 1530 | * NR_CPUS + KERNEL_STACK_SIZE); |
1454 | mca_data = (void *)(((unsigned long)mca_data + | 1531 | mca_data = (void *)(((unsigned long)mca_data + |
@@ -1704,6 +1781,7 @@ ia64_mca_late_init(void) | |||
1704 | desc = irq_descp(irq); | 1781 | desc = irq_descp(irq); |
1705 | desc->status |= IRQ_PER_CPU; | 1782 | desc->status |= IRQ_PER_CPU; |
1706 | setup_irq(irq, &mca_cpe_irqaction); | 1783 | setup_irq(irq, &mca_cpe_irqaction); |
1784 | ia64_cpe_irq = irq; | ||
1707 | } | 1785 | } |
1708 | ia64_mca_register_cpev(cpe_vector); | 1786 | ia64_mca_register_cpev(cpe_vector); |
1709 | IA64_MCA_DEBUG("%s: CPEI/P setup and enabled.\n", __FUNCTION__); | 1787 | IA64_MCA_DEBUG("%s: CPEI/P setup and enabled.\n", __FUNCTION__); |
diff --git a/arch/ia64/kernel/mca_drv.c b/arch/ia64/kernel/mca_drv.c index e883d85906db..37c88eb55873 100644 --- a/arch/ia64/kernel/mca_drv.c +++ b/arch/ia64/kernel/mca_drv.c | |||
@@ -6,6 +6,7 @@ | |||
6 | * Copyright (C) Hidetoshi Seto (seto.hidetoshi@jp.fujitsu.com) | 6 | * Copyright (C) Hidetoshi Seto (seto.hidetoshi@jp.fujitsu.com) |
7 | * Copyright (C) 2005 Silicon Graphics, Inc | 7 | * Copyright (C) 2005 Silicon Graphics, Inc |
8 | * Copyright (C) 2005 Keith Owens <kaos@sgi.com> | 8 | * Copyright (C) 2005 Keith Owens <kaos@sgi.com> |
9 | * Copyright (C) 2006 Russ Anderson <rja@sgi.com> | ||
9 | */ | 10 | */ |
10 | #include <linux/config.h> | 11 | #include <linux/config.h> |
11 | #include <linux/types.h> | 12 | #include <linux/types.h> |
@@ -121,11 +122,12 @@ mca_page_isolate(unsigned long paddr) | |||
121 | */ | 122 | */ |
122 | 123 | ||
123 | void | 124 | void |
124 | mca_handler_bh(unsigned long paddr) | 125 | mca_handler_bh(unsigned long paddr, void *iip, unsigned long ipsr) |
125 | { | 126 | { |
126 | printk(KERN_ERR | 127 | printk(KERN_ERR "OS_MCA: process [cpu %d, pid: %d, uid: %d, " |
127 | "OS_MCA: process [pid: %d](%s) encounters MCA (paddr=%lx)\n", | 128 | "iip: %p, psr: 0x%lx,paddr: 0x%lx](%s) encounters MCA.\n", |
128 | current->pid, current->comm, paddr); | 129 | raw_smp_processor_id(), current->pid, current->uid, |
130 | iip, ipsr, paddr, current->comm); | ||
129 | 131 | ||
130 | spin_lock(&mca_bh_lock); | 132 | spin_lock(&mca_bh_lock); |
131 | switch (mca_page_isolate(paddr)) { | 133 | switch (mca_page_isolate(paddr)) { |
@@ -442,21 +444,26 @@ recover_from_read_error(slidx_table_t *slidx, | |||
442 | if (!peidx_bottom(peidx) || !(peidx_bottom(peidx)->valid.minstate)) | 444 | if (!peidx_bottom(peidx) || !(peidx_bottom(peidx)->valid.minstate)) |
443 | return 0; | 445 | return 0; |
444 | psr1 =(struct ia64_psr *)&(peidx_minstate_area(peidx)->pmsa_ipsr); | 446 | psr1 =(struct ia64_psr *)&(peidx_minstate_area(peidx)->pmsa_ipsr); |
447 | psr2 =(struct ia64_psr *)&(peidx_minstate_area(peidx)->pmsa_xpsr); | ||
445 | 448 | ||
446 | /* | 449 | /* |
447 | * Check the privilege level of interrupted context. | 450 | * Check the privilege level of interrupted context. |
448 | * If it is user-mode, then terminate affected process. | 451 | * If it is user-mode, then terminate affected process. |
449 | */ | 452 | */ |
450 | if (psr1->cpl != 0) { | 453 | |
454 | pmsa = sos->pal_min_state; | ||
455 | if (psr1->cpl != 0 || | ||
456 | ((psr2->cpl != 0) && mca_recover_range(pmsa->pmsa_iip))) { | ||
451 | smei = peidx_bus_check(peidx, 0); | 457 | smei = peidx_bus_check(peidx, 0); |
452 | if (smei->valid.target_identifier) { | 458 | if (smei->valid.target_identifier) { |
453 | /* | 459 | /* |
454 | * setup for resume to bottom half of MCA, | 460 | * setup for resume to bottom half of MCA, |
455 | * "mca_handler_bhhook" | 461 | * "mca_handler_bhhook" |
456 | */ | 462 | */ |
457 | pmsa = sos->pal_min_state; | 463 | /* pass to bhhook as argument (gr8, ...) */ |
458 | /* pass to bhhook as 1st argument (gr8) */ | ||
459 | pmsa->pmsa_gr[8-1] = smei->target_identifier; | 464 | pmsa->pmsa_gr[8-1] = smei->target_identifier; |
465 | pmsa->pmsa_gr[9-1] = pmsa->pmsa_iip; | ||
466 | pmsa->pmsa_gr[10-1] = pmsa->pmsa_ipsr; | ||
460 | /* set interrupted return address (but no use) */ | 467 | /* set interrupted return address (but no use) */ |
461 | pmsa->pmsa_br0 = pmsa->pmsa_iip; | 468 | pmsa->pmsa_br0 = pmsa->pmsa_iip; |
462 | /* change resume address to bottom half */ | 469 | /* change resume address to bottom half */ |
@@ -466,6 +473,7 @@ recover_from_read_error(slidx_table_t *slidx, | |||
466 | psr2 = (struct ia64_psr *)&pmsa->pmsa_ipsr; | 473 | psr2 = (struct ia64_psr *)&pmsa->pmsa_ipsr; |
467 | psr2->cpl = 0; | 474 | psr2->cpl = 0; |
468 | psr2->ri = 0; | 475 | psr2->ri = 0; |
476 | psr2->bn = 1; | ||
469 | psr2->i = 0; | 477 | psr2->i = 0; |
470 | 478 | ||
471 | return 1; | 479 | return 1; |
diff --git a/arch/ia64/kernel/mca_drv.h b/arch/ia64/kernel/mca_drv.h index e2f6fa1e0ef6..31a2e52bb16f 100644 --- a/arch/ia64/kernel/mca_drv.h +++ b/arch/ia64/kernel/mca_drv.h | |||
@@ -111,3 +111,10 @@ typedef struct slidx_table { | |||
111 | slidx_foreach_entry(__pos, &((slidx)->sec)) { __count++; }\ | 111 | slidx_foreach_entry(__pos, &((slidx)->sec)) { __count++; }\ |
112 | __count; }) | 112 | __count; }) |
113 | 113 | ||
114 | struct mca_table_entry { | ||
115 | int start_addr; /* location-relative starting address of MCA recoverable range */ | ||
116 | int end_addr; /* location-relative ending address of MCA recoverable range */ | ||
117 | }; | ||
118 | |||
119 | extern const struct mca_table_entry *search_mca_tables (unsigned long addr); | ||
120 | extern int mca_recover_range(unsigned long); | ||
diff --git a/arch/ia64/kernel/mca_drv_asm.S b/arch/ia64/kernel/mca_drv_asm.S index 3f298ee4d00c..e6a580d354b9 100644 --- a/arch/ia64/kernel/mca_drv_asm.S +++ b/arch/ia64/kernel/mca_drv_asm.S | |||
@@ -14,15 +14,12 @@ | |||
14 | 14 | ||
15 | GLOBAL_ENTRY(mca_handler_bhhook) | 15 | GLOBAL_ENTRY(mca_handler_bhhook) |
16 | invala // clear RSE ? | 16 | invala // clear RSE ? |
17 | ;; | ||
18 | cover | 17 | cover |
19 | ;; | 18 | ;; |
20 | clrrrb | 19 | clrrrb |
21 | ;; | 20 | ;; |
22 | alloc r16=ar.pfs,0,2,1,0 // make a new frame | 21 | alloc r16=ar.pfs,0,2,3,0 // make a new frame |
23 | ;; | ||
24 | mov ar.rsc=0 | 22 | mov ar.rsc=0 |
25 | ;; | ||
26 | mov r13=IA64_KR(CURRENT) // current task pointer | 23 | mov r13=IA64_KR(CURRENT) // current task pointer |
27 | ;; | 24 | ;; |
28 | mov r2=r13 | 25 | mov r2=r13 |
@@ -30,7 +27,6 @@ GLOBAL_ENTRY(mca_handler_bhhook) | |||
30 | addl r22=IA64_RBS_OFFSET,r2 | 27 | addl r22=IA64_RBS_OFFSET,r2 |
31 | ;; | 28 | ;; |
32 | mov ar.bspstore=r22 | 29 | mov ar.bspstore=r22 |
33 | ;; | ||
34 | addl sp=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r2 | 30 | addl sp=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r2 |
35 | ;; | 31 | ;; |
36 | adds r2=IA64_TASK_THREAD_ON_USTACK_OFFSET,r13 | 32 | adds r2=IA64_TASK_THREAD_ON_USTACK_OFFSET,r13 |
@@ -40,12 +36,12 @@ GLOBAL_ENTRY(mca_handler_bhhook) | |||
40 | movl loc1=mca_handler_bh // recovery C function | 36 | movl loc1=mca_handler_bh // recovery C function |
41 | ;; | 37 | ;; |
42 | mov out0=r8 // poisoned address | 38 | mov out0=r8 // poisoned address |
39 | mov out1=r9 // iip | ||
40 | mov out2=r10 // psr | ||
43 | mov b6=loc1 | 41 | mov b6=loc1 |
44 | ;; | 42 | ;; |
45 | mov loc1=rp | 43 | mov loc1=rp |
46 | ;; | 44 | ssm psr.i | psr.ic |
47 | ssm psr.i | ||
48 | ;; | ||
49 | br.call.sptk.many rp=b6 // does not return ... | 45 | br.call.sptk.many rp=b6 // does not return ... |
50 | ;; | 46 | ;; |
51 | mov ar.pfs=loc0 | 47 | mov ar.pfs=loc0 |
@@ -53,5 +49,4 @@ GLOBAL_ENTRY(mca_handler_bhhook) | |||
53 | ;; | 49 | ;; |
54 | mov r8=r0 | 50 | mov r8=r0 |
55 | br.ret.sptk.many rp | 51 | br.ret.sptk.many rp |
56 | ;; | ||
57 | END(mca_handler_bhhook) | 52 | END(mca_handler_bhhook) |
diff --git a/arch/ia64/kernel/numa.c b/arch/ia64/kernel/numa.c index a68ce6678092..0766493d4d00 100644 --- a/arch/ia64/kernel/numa.c +++ b/arch/ia64/kernel/numa.c | |||
@@ -25,7 +25,7 @@ | |||
25 | #include <asm/processor.h> | 25 | #include <asm/processor.h> |
26 | #include <asm/smp.h> | 26 | #include <asm/smp.h> |
27 | 27 | ||
28 | u8 cpu_to_node_map[NR_CPUS] __cacheline_aligned; | 28 | u16 cpu_to_node_map[NR_CPUS] __cacheline_aligned; |
29 | EXPORT_SYMBOL(cpu_to_node_map); | 29 | EXPORT_SYMBOL(cpu_to_node_map); |
30 | 30 | ||
31 | cpumask_t node_to_cpu_mask[MAX_NUMNODES] __cacheline_aligned; | 31 | cpumask_t node_to_cpu_mask[MAX_NUMNODES] __cacheline_aligned; |
diff --git a/arch/ia64/kernel/patch.c b/arch/ia64/kernel/patch.c index 6a4ac7d70b35..bc11bb096f58 100644 --- a/arch/ia64/kernel/patch.c +++ b/arch/ia64/kernel/patch.c | |||
@@ -115,7 +115,7 @@ ia64_patch_vtop (unsigned long start, unsigned long end) | |||
115 | ia64_srlz_i(); | 115 | ia64_srlz_i(); |
116 | } | 116 | } |
117 | 117 | ||
118 | void | 118 | void __init |
119 | ia64_patch_mckinley_e9 (unsigned long start, unsigned long end) | 119 | ia64_patch_mckinley_e9 (unsigned long start, unsigned long end) |
120 | { | 120 | { |
121 | static int first_time = 1; | 121 | static int first_time = 1; |
@@ -149,7 +149,7 @@ ia64_patch_mckinley_e9 (unsigned long start, unsigned long end) | |||
149 | ia64_srlz_i(); | 149 | ia64_srlz_i(); |
150 | } | 150 | } |
151 | 151 | ||
152 | static void | 152 | static void __init |
153 | patch_fsyscall_table (unsigned long start, unsigned long end) | 153 | patch_fsyscall_table (unsigned long start, unsigned long end) |
154 | { | 154 | { |
155 | extern unsigned long fsyscall_table[NR_syscalls]; | 155 | extern unsigned long fsyscall_table[NR_syscalls]; |
@@ -166,7 +166,7 @@ patch_fsyscall_table (unsigned long start, unsigned long end) | |||
166 | ia64_srlz_i(); | 166 | ia64_srlz_i(); |
167 | } | 167 | } |
168 | 168 | ||
169 | static void | 169 | static void __init |
170 | patch_brl_fsys_bubble_down (unsigned long start, unsigned long end) | 170 | patch_brl_fsys_bubble_down (unsigned long start, unsigned long end) |
171 | { | 171 | { |
172 | extern char fsys_bubble_down[]; | 172 | extern char fsys_bubble_down[]; |
@@ -184,7 +184,7 @@ patch_brl_fsys_bubble_down (unsigned long start, unsigned long end) | |||
184 | ia64_srlz_i(); | 184 | ia64_srlz_i(); |
185 | } | 185 | } |
186 | 186 | ||
187 | void | 187 | void __init |
188 | ia64_patch_gate (void) | 188 | ia64_patch_gate (void) |
189 | { | 189 | { |
190 | # define START(name) ((unsigned long) __start_gate_##name##_patchlist) | 190 | # define START(name) ((unsigned long) __start_gate_##name##_patchlist) |
diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c index 9c5194b385da..077f21216b65 100644 --- a/arch/ia64/kernel/perfmon.c +++ b/arch/ia64/kernel/perfmon.c | |||
@@ -6722,6 +6722,7 @@ __initcall(pfm_init); | |||
6722 | void | 6722 | void |
6723 | pfm_init_percpu (void) | 6723 | pfm_init_percpu (void) |
6724 | { | 6724 | { |
6725 | static int first_time=1; | ||
6725 | /* | 6726 | /* |
6726 | * make sure no measurement is active | 6727 | * make sure no measurement is active |
6727 | * (may inherit programmed PMCs from EFI). | 6728 | * (may inherit programmed PMCs from EFI). |
@@ -6734,8 +6735,10 @@ pfm_init_percpu (void) | |||
6734 | */ | 6735 | */ |
6735 | pfm_unfreeze_pmu(); | 6736 | pfm_unfreeze_pmu(); |
6736 | 6737 | ||
6737 | if (smp_processor_id() == 0) | 6738 | if (first_time) { |
6738 | register_percpu_irq(IA64_PERFMON_VECTOR, &perfmon_irqaction); | 6739 | register_percpu_irq(IA64_PERFMON_VECTOR, &perfmon_irqaction); |
6740 | first_time=0; | ||
6741 | } | ||
6739 | 6742 | ||
6740 | ia64_setreg(_IA64_REG_CR_PMV, IA64_PERFMON_VECTOR); | 6743 | ia64_setreg(_IA64_REG_CR_PMV, IA64_PERFMON_VECTOR); |
6741 | ia64_srlz_d(); | 6744 | ia64_srlz_d(); |
diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c index 3258e09278d0..eb388e271b2b 100644 --- a/arch/ia64/kernel/setup.c +++ b/arch/ia64/kernel/setup.c | |||
@@ -41,7 +41,6 @@ | |||
41 | #include <linux/serial_core.h> | 41 | #include <linux/serial_core.h> |
42 | #include <linux/efi.h> | 42 | #include <linux/efi.h> |
43 | #include <linux/initrd.h> | 43 | #include <linux/initrd.h> |
44 | #include <linux/platform.h> | ||
45 | #include <linux/pm.h> | 44 | #include <linux/pm.h> |
46 | #include <linux/cpufreq.h> | 45 | #include <linux/cpufreq.h> |
47 | 46 | ||
@@ -131,8 +130,8 @@ EXPORT_SYMBOL(ia64_max_iommu_merge_mask); | |||
131 | /* | 130 | /* |
132 | * We use a special marker for the end of memory and it uses the extra (+1) slot | 131 | * We use a special marker for the end of memory and it uses the extra (+1) slot |
133 | */ | 132 | */ |
134 | struct rsvd_region rsvd_region[IA64_MAX_RSVD_REGIONS + 1]; | 133 | struct rsvd_region rsvd_region[IA64_MAX_RSVD_REGIONS + 1] __initdata; |
135 | int num_rsvd_regions; | 134 | int num_rsvd_regions __initdata; |
136 | 135 | ||
137 | 136 | ||
138 | /* | 137 | /* |
@@ -141,7 +140,7 @@ int num_rsvd_regions; | |||
141 | * caller-specified function is called with the memory ranges that remain after filtering. | 140 | * caller-specified function is called with the memory ranges that remain after filtering. |
142 | * This routine does not assume the incoming segments are sorted. | 141 | * This routine does not assume the incoming segments are sorted. |
143 | */ | 142 | */ |
144 | int | 143 | int __init |
145 | filter_rsvd_memory (unsigned long start, unsigned long end, void *arg) | 144 | filter_rsvd_memory (unsigned long start, unsigned long end, void *arg) |
146 | { | 145 | { |
147 | unsigned long range_start, range_end, prev_start; | 146 | unsigned long range_start, range_end, prev_start; |
@@ -177,7 +176,7 @@ filter_rsvd_memory (unsigned long start, unsigned long end, void *arg) | |||
177 | return 0; | 176 | return 0; |
178 | } | 177 | } |
179 | 178 | ||
180 | static void | 179 | static void __init |
181 | sort_regions (struct rsvd_region *rsvd_region, int max) | 180 | sort_regions (struct rsvd_region *rsvd_region, int max) |
182 | { | 181 | { |
183 | int j; | 182 | int j; |
@@ -218,7 +217,7 @@ __initcall(register_memory); | |||
218 | * initrd, etc. There are currently %IA64_MAX_RSVD_REGIONS defined, | 217 | * initrd, etc. There are currently %IA64_MAX_RSVD_REGIONS defined, |
219 | * see include/asm-ia64/meminit.h if you need to define more. | 218 | * see include/asm-ia64/meminit.h if you need to define more. |
220 | */ | 219 | */ |
221 | void | 220 | void __init |
222 | reserve_memory (void) | 221 | reserve_memory (void) |
223 | { | 222 | { |
224 | int n = 0; | 223 | int n = 0; |
@@ -270,7 +269,7 @@ reserve_memory (void) | |||
270 | * Grab the initrd start and end from the boot parameter struct given us by | 269 | * Grab the initrd start and end from the boot parameter struct given us by |
271 | * the boot loader. | 270 | * the boot loader. |
272 | */ | 271 | */ |
273 | void | 272 | void __init |
274 | find_initrd (void) | 273 | find_initrd (void) |
275 | { | 274 | { |
276 | #ifdef CONFIG_BLK_DEV_INITRD | 275 | #ifdef CONFIG_BLK_DEV_INITRD |
@@ -362,7 +361,7 @@ mark_bsp_online (void) | |||
362 | } | 361 | } |
363 | 362 | ||
364 | #ifdef CONFIG_SMP | 363 | #ifdef CONFIG_SMP |
365 | static void | 364 | static void __init |
366 | check_for_logical_procs (void) | 365 | check_for_logical_procs (void) |
367 | { | 366 | { |
368 | pal_logical_to_physical_t info; | 367 | pal_logical_to_physical_t info; |
@@ -389,6 +388,14 @@ check_for_logical_procs (void) | |||
389 | } | 388 | } |
390 | #endif | 389 | #endif |
391 | 390 | ||
391 | static __initdata int nomca; | ||
392 | static __init int setup_nomca(char *s) | ||
393 | { | ||
394 | nomca = 1; | ||
395 | return 0; | ||
396 | } | ||
397 | early_param("nomca", setup_nomca); | ||
398 | |||
392 | void __init | 399 | void __init |
393 | setup_arch (char **cmdline_p) | 400 | setup_arch (char **cmdline_p) |
394 | { | 401 | { |
@@ -402,35 +409,15 @@ setup_arch (char **cmdline_p) | |||
402 | efi_init(); | 409 | efi_init(); |
403 | io_port_init(); | 410 | io_port_init(); |
404 | 411 | ||
412 | parse_early_param(); | ||
413 | |||
405 | #ifdef CONFIG_IA64_GENERIC | 414 | #ifdef CONFIG_IA64_GENERIC |
406 | { | 415 | machvec_init(NULL); |
407 | const char *mvec_name = strstr (*cmdline_p, "machvec="); | ||
408 | char str[64]; | ||
409 | |||
410 | if (mvec_name) { | ||
411 | const char *end; | ||
412 | size_t len; | ||
413 | |||
414 | mvec_name += 8; | ||
415 | end = strchr (mvec_name, ' '); | ||
416 | if (end) | ||
417 | len = end - mvec_name; | ||
418 | else | ||
419 | len = strlen (mvec_name); | ||
420 | len = min(len, sizeof (str) - 1); | ||
421 | strncpy (str, mvec_name, len); | ||
422 | str[len] = '\0'; | ||
423 | mvec_name = str; | ||
424 | } else | ||
425 | mvec_name = acpi_get_sysname(); | ||
426 | machvec_init(mvec_name); | ||
427 | } | ||
428 | #endif | 416 | #endif |
429 | 417 | ||
430 | if (early_console_setup(*cmdline_p) == 0) | 418 | if (early_console_setup(*cmdline_p) == 0) |
431 | mark_bsp_online(); | 419 | mark_bsp_online(); |
432 | 420 | ||
433 | parse_early_param(); | ||
434 | #ifdef CONFIG_ACPI | 421 | #ifdef CONFIG_ACPI |
435 | /* Initialize the ACPI boot-time table parser */ | 422 | /* Initialize the ACPI boot-time table parser */ |
436 | acpi_table_init(); | 423 | acpi_table_init(); |
@@ -493,7 +480,7 @@ setup_arch (char **cmdline_p) | |||
493 | #endif | 480 | #endif |
494 | 481 | ||
495 | /* enable IA-64 Machine Check Abort Handling unless disabled */ | 482 | /* enable IA-64 Machine Check Abort Handling unless disabled */ |
496 | if (!strstr(saved_command_line, "nomca")) | 483 | if (!nomca) |
497 | ia64_mca_init(); | 484 | ia64_mca_init(); |
498 | 485 | ||
499 | platform_setup(cmdline_p); | 486 | platform_setup(cmdline_p); |
@@ -623,7 +610,7 @@ struct seq_operations cpuinfo_op = { | |||
623 | .show = show_cpuinfo | 610 | .show = show_cpuinfo |
624 | }; | 611 | }; |
625 | 612 | ||
626 | void | 613 | static void __cpuinit |
627 | identify_cpu (struct cpuinfo_ia64 *c) | 614 | identify_cpu (struct cpuinfo_ia64 *c) |
628 | { | 615 | { |
629 | union { | 616 | union { |
@@ -700,7 +687,7 @@ setup_per_cpu_areas (void) | |||
700 | * In addition, the minimum of the i-cache stride sizes is calculated for | 687 | * In addition, the minimum of the i-cache stride sizes is calculated for |
701 | * "flush_icache_range()". | 688 | * "flush_icache_range()". |
702 | */ | 689 | */ |
703 | static void | 690 | static void __cpuinit |
704 | get_max_cacheline_size (void) | 691 | get_max_cacheline_size (void) |
705 | { | 692 | { |
706 | unsigned long line_size, max = 1; | 693 | unsigned long line_size, max = 1; |
@@ -763,10 +750,10 @@ get_max_cacheline_size (void) | |||
763 | * cpu_init() initializes state that is per-CPU. This function acts | 750 | * cpu_init() initializes state that is per-CPU. This function acts |
764 | * as a 'CPU state barrier', nothing should get across. | 751 | * as a 'CPU state barrier', nothing should get across. |
765 | */ | 752 | */ |
766 | void | 753 | void __cpuinit |
767 | cpu_init (void) | 754 | cpu_init (void) |
768 | { | 755 | { |
769 | extern void __devinit ia64_mmu_init (void *); | 756 | extern void __cpuinit ia64_mmu_init (void *); |
770 | unsigned long num_phys_stacked; | 757 | unsigned long num_phys_stacked; |
771 | pal_vm_info_2_u_t vmi; | 758 | pal_vm_info_2_u_t vmi; |
772 | unsigned int max_ctx; | 759 | unsigned int max_ctx; |
@@ -894,7 +881,7 @@ void sched_cacheflush(void) | |||
894 | ia64_sal_cache_flush(3); | 881 | ia64_sal_cache_flush(3); |
895 | } | 882 | } |
896 | 883 | ||
897 | void | 884 | void __init |
898 | check_bugs (void) | 885 | check_bugs (void) |
899 | { | 886 | { |
900 | ia64_patch_mckinley_e9((unsigned long) __start___mckinley_e9_bundles, | 887 | ia64_patch_mckinley_e9((unsigned long) __start___mckinley_e9_bundles, |
diff --git a/arch/ia64/kernel/signal.c b/arch/ia64/kernel/signal.c index 463f6bb44d07..1d7903ee2126 100644 --- a/arch/ia64/kernel/signal.c +++ b/arch/ia64/kernel/signal.c | |||
@@ -588,104 +588,3 @@ ia64_do_signal (sigset_t *oldset, struct sigscratch *scr, long in_syscall) | |||
588 | } | 588 | } |
589 | return 0; | 589 | return 0; |
590 | } | 590 | } |
591 | |||
592 | /* Set a delayed signal that was detected in MCA/INIT/NMI/PMI context where it | ||
593 | * could not be delivered. It is important that the target process is not | ||
594 | * allowed to do any more work in user space. Possible cases for the target | ||
595 | * process: | ||
596 | * | ||
597 | * - It is sleeping and will wake up soon. Store the data in the current task, | ||
598 | * the signal will be sent when the current task returns from the next | ||
599 | * interrupt. | ||
600 | * | ||
601 | * - It is running in user context. Store the data in the current task, the | ||
602 | * signal will be sent when the current task returns from the next interrupt. | ||
603 | * | ||
604 | * - It is running in kernel context on this or another cpu and will return to | ||
605 | * user context. Store the data in the target task, the signal will be sent | ||
606 | * to itself when the target task returns to user space. | ||
607 | * | ||
608 | * - It is running in kernel context on this cpu and will sleep before | ||
609 | * returning to user context. Because this is also the current task, the | ||
610 | * signal will not get delivered and the task could sleep indefinitely. | ||
611 | * Store the data in the idle task for this cpu, the signal will be sent | ||
612 | * after the idle task processes its next interrupt. | ||
613 | * | ||
614 | * To cover all cases, store the data in the target task, the current task and | ||
615 | * the idle task on this cpu. Whatever happens, the signal will be delivered | ||
616 | * to the target task before it can do any useful user space work. Multiple | ||
617 | * deliveries have no unwanted side effects. | ||
618 | * | ||
619 | * Note: This code is executed in MCA/INIT/NMI/PMI context, with interrupts | ||
620 | * disabled. It must not take any locks nor use kernel structures or services | ||
621 | * that require locks. | ||
622 | */ | ||
623 | |||
624 | /* To ensure that we get the right pid, check its start time. To avoid extra | ||
625 | * include files in thread_info.h, convert the task start_time to unsigned long, | ||
626 | * giving us a cycle time of > 580 years. | ||
627 | */ | ||
628 | static inline unsigned long | ||
629 | start_time_ul(const struct task_struct *t) | ||
630 | { | ||
631 | return t->start_time.tv_sec * NSEC_PER_SEC + t->start_time.tv_nsec; | ||
632 | } | ||
633 | |||
634 | void | ||
635 | set_sigdelayed(pid_t pid, int signo, int code, void __user *addr) | ||
636 | { | ||
637 | struct task_struct *t; | ||
638 | unsigned long start_time = 0; | ||
639 | int i; | ||
640 | |||
641 | for (i = 1; i <= 3; ++i) { | ||
642 | switch (i) { | ||
643 | case 1: | ||
644 | t = find_task_by_pid(pid); | ||
645 | if (t) | ||
646 | start_time = start_time_ul(t); | ||
647 | break; | ||
648 | case 2: | ||
649 | t = current; | ||
650 | break; | ||
651 | default: | ||
652 | t = idle_task(smp_processor_id()); | ||
653 | break; | ||
654 | } | ||
655 | |||
656 | if (!t) | ||
657 | return; | ||
658 | task_thread_info(t)->sigdelayed.signo = signo; | ||
659 | task_thread_info(t)->sigdelayed.code = code; | ||
660 | task_thread_info(t)->sigdelayed.addr = addr; | ||
661 | task_thread_info(t)->sigdelayed.start_time = start_time; | ||
662 | task_thread_info(t)->sigdelayed.pid = pid; | ||
663 | wmb(); | ||
664 | set_tsk_thread_flag(t, TIF_SIGDELAYED); | ||
665 | } | ||
666 | } | ||
667 | |||
668 | /* Called from entry.S when it detects TIF_SIGDELAYED, a delayed signal that | ||
669 | * was detected in MCA/INIT/NMI/PMI context where it could not be delivered. | ||
670 | */ | ||
671 | |||
672 | void | ||
673 | do_sigdelayed(void) | ||
674 | { | ||
675 | struct siginfo siginfo; | ||
676 | pid_t pid; | ||
677 | struct task_struct *t; | ||
678 | |||
679 | clear_thread_flag(TIF_SIGDELAYED); | ||
680 | memset(&siginfo, 0, sizeof(siginfo)); | ||
681 | siginfo.si_signo = current_thread_info()->sigdelayed.signo; | ||
682 | siginfo.si_code = current_thread_info()->sigdelayed.code; | ||
683 | siginfo.si_addr = current_thread_info()->sigdelayed.addr; | ||
684 | pid = current_thread_info()->sigdelayed.pid; | ||
685 | t = find_task_by_pid(pid); | ||
686 | if (!t) | ||
687 | return; | ||
688 | if (current_thread_info()->sigdelayed.start_time != start_time_ul(t)) | ||
689 | return; | ||
690 | force_sig_info(siginfo.si_signo, &siginfo, t); | ||
691 | } | ||
diff --git a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c index b681ef34a86e..44e9547878ac 100644 --- a/arch/ia64/kernel/smpboot.c +++ b/arch/ia64/kernel/smpboot.c | |||
@@ -70,6 +70,12 @@ | |||
70 | #endif | 70 | #endif |
71 | 71 | ||
72 | #ifdef CONFIG_HOTPLUG_CPU | 72 | #ifdef CONFIG_HOTPLUG_CPU |
73 | #ifdef CONFIG_PERMIT_BSP_REMOVE | ||
74 | #define bsp_remove_ok 1 | ||
75 | #else | ||
76 | #define bsp_remove_ok 0 | ||
77 | #endif | ||
78 | |||
73 | /* | 79 | /* |
74 | * Store all idle threads, this can be reused instead of creating | 80 | * Store all idle threads, this can be reused instead of creating |
75 | * a new thread. Also avoids complicated thread destroy functionality | 81 | * a new thread. Also avoids complicated thread destroy functionality |
@@ -104,7 +110,7 @@ struct sal_to_os_boot *sal_state_for_booting_cpu = &sal_boot_rendez_state[0]; | |||
104 | /* | 110 | /* |
105 | * ITC synchronization related stuff: | 111 | * ITC synchronization related stuff: |
106 | */ | 112 | */ |
107 | #define MASTER 0 | 113 | #define MASTER (0) |
108 | #define SLAVE (SMP_CACHE_BYTES/8) | 114 | #define SLAVE (SMP_CACHE_BYTES/8) |
109 | 115 | ||
110 | #define NUM_ROUNDS 64 /* magic value */ | 116 | #define NUM_ROUNDS 64 /* magic value */ |
@@ -151,6 +157,27 @@ char __initdata no_int_routing; | |||
151 | 157 | ||
152 | unsigned char smp_int_redirect; /* are INT and IPI redirectable by the chipset? */ | 158 | unsigned char smp_int_redirect; /* are INT and IPI redirectable by the chipset? */ |
153 | 159 | ||
160 | #ifdef CONFIG_FORCE_CPEI_RETARGET | ||
161 | #define CPEI_OVERRIDE_DEFAULT (1) | ||
162 | #else | ||
163 | #define CPEI_OVERRIDE_DEFAULT (0) | ||
164 | #endif | ||
165 | |||
166 | unsigned int force_cpei_retarget = CPEI_OVERRIDE_DEFAULT; | ||
167 | |||
168 | static int __init | ||
169 | cmdl_force_cpei(char *str) | ||
170 | { | ||
171 | int value=0; | ||
172 | |||
173 | get_option (&str, &value); | ||
174 | force_cpei_retarget = value; | ||
175 | |||
176 | return 1; | ||
177 | } | ||
178 | |||
179 | __setup("force_cpei=", cmdl_force_cpei); | ||
180 | |||
154 | static int __init | 181 | static int __init |
155 | nointroute (char *str) | 182 | nointroute (char *str) |
156 | { | 183 | { |
@@ -161,6 +188,27 @@ nointroute (char *str) | |||
161 | 188 | ||
162 | __setup("nointroute", nointroute); | 189 | __setup("nointroute", nointroute); |
163 | 190 | ||
191 | static void fix_b0_for_bsp(void) | ||
192 | { | ||
193 | #ifdef CONFIG_HOTPLUG_CPU | ||
194 | int cpuid; | ||
195 | static int fix_bsp_b0 = 1; | ||
196 | |||
197 | cpuid = smp_processor_id(); | ||
198 | |||
199 | /* | ||
200 | * Cache the b0 value on the first AP that comes up | ||
201 | */ | ||
202 | if (!(fix_bsp_b0 && cpuid)) | ||
203 | return; | ||
204 | |||
205 | sal_boot_rendez_state[0].br[0] = sal_boot_rendez_state[cpuid].br[0]; | ||
206 | printk ("Fixed BSP b0 value from CPU %d\n", cpuid); | ||
207 | |||
208 | fix_bsp_b0 = 0; | ||
209 | #endif | ||
210 | } | ||
211 | |||
164 | void | 212 | void |
165 | sync_master (void *arg) | 213 | sync_master (void *arg) |
166 | { | 214 | { |
@@ -327,8 +375,9 @@ smp_setup_percpu_timer (void) | |||
327 | static void __devinit | 375 | static void __devinit |
328 | smp_callin (void) | 376 | smp_callin (void) |
329 | { | 377 | { |
330 | int cpuid, phys_id; | 378 | int cpuid, phys_id, itc_master; |
331 | extern void ia64_init_itm(void); | 379 | extern void ia64_init_itm(void); |
380 | extern volatile int time_keeper_id; | ||
332 | 381 | ||
333 | #ifdef CONFIG_PERFMON | 382 | #ifdef CONFIG_PERFMON |
334 | extern void pfm_init_percpu(void); | 383 | extern void pfm_init_percpu(void); |
@@ -336,6 +385,7 @@ smp_callin (void) | |||
336 | 385 | ||
337 | cpuid = smp_processor_id(); | 386 | cpuid = smp_processor_id(); |
338 | phys_id = hard_smp_processor_id(); | 387 | phys_id = hard_smp_processor_id(); |
388 | itc_master = time_keeper_id; | ||
339 | 389 | ||
340 | if (cpu_online(cpuid)) { | 390 | if (cpu_online(cpuid)) { |
341 | printk(KERN_ERR "huh, phys CPU#0x%x, CPU#0x%x already present??\n", | 391 | printk(KERN_ERR "huh, phys CPU#0x%x, CPU#0x%x already present??\n", |
@@ -343,6 +393,8 @@ smp_callin (void) | |||
343 | BUG(); | 393 | BUG(); |
344 | } | 394 | } |
345 | 395 | ||
396 | fix_b0_for_bsp(); | ||
397 | |||
346 | lock_ipi_calllock(); | 398 | lock_ipi_calllock(); |
347 | cpu_set(cpuid, cpu_online_map); | 399 | cpu_set(cpuid, cpu_online_map); |
348 | unlock_ipi_calllock(); | 400 | unlock_ipi_calllock(); |
@@ -365,8 +417,8 @@ smp_callin (void) | |||
365 | * calls spin_unlock_bh(), which calls spin_unlock_bh(), which calls | 417 | * calls spin_unlock_bh(), which calls spin_unlock_bh(), which calls |
366 | * local_bh_enable(), which bugs out if irqs are not enabled... | 418 | * local_bh_enable(), which bugs out if irqs are not enabled... |
367 | */ | 419 | */ |
368 | Dprintk("Going to syncup ITC with BP.\n"); | 420 | Dprintk("Going to syncup ITC with ITC Master.\n"); |
369 | ia64_sync_itc(0); | 421 | ia64_sync_itc(itc_master); |
370 | } | 422 | } |
371 | 423 | ||
372 | /* | 424 | /* |
@@ -572,32 +624,8 @@ void __devinit smp_prepare_boot_cpu(void) | |||
572 | per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE; | 624 | per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE; |
573 | } | 625 | } |
574 | 626 | ||
575 | /* | ||
576 | * mt_info[] is a temporary store for all info returned by | ||
577 | * PAL_LOGICAL_TO_PHYSICAL, to be copied into cpuinfo_ia64 when the | ||
578 | * specific cpu comes. | ||
579 | */ | ||
580 | static struct { | ||
581 | __u32 socket_id; | ||
582 | __u16 core_id; | ||
583 | __u16 thread_id; | ||
584 | __u16 proc_fixed_addr; | ||
585 | __u8 valid; | ||
586 | } mt_info[NR_CPUS] __devinitdata; | ||
587 | |||
588 | #ifdef CONFIG_HOTPLUG_CPU | 627 | #ifdef CONFIG_HOTPLUG_CPU |
589 | static inline void | 628 | static inline void |
590 | remove_from_mtinfo(int cpu) | ||
591 | { | ||
592 | int i; | ||
593 | |||
594 | for_each_cpu(i) | ||
595 | if (mt_info[i].valid && mt_info[i].socket_id == | ||
596 | cpu_data(cpu)->socket_id) | ||
597 | mt_info[i].valid = 0; | ||
598 | } | ||
599 | |||
600 | static inline void | ||
601 | clear_cpu_sibling_map(int cpu) | 629 | clear_cpu_sibling_map(int cpu) |
602 | { | 630 | { |
603 | int i; | 631 | int i; |
@@ -626,15 +654,50 @@ remove_siblinginfo(int cpu) | |||
626 | 654 | ||
627 | /* remove it from all sibling map's */ | 655 | /* remove it from all sibling map's */ |
628 | clear_cpu_sibling_map(cpu); | 656 | clear_cpu_sibling_map(cpu); |
657 | } | ||
658 | |||
659 | extern void fixup_irqs(void); | ||
629 | 660 | ||
630 | /* if this cpu is the last in the core group, remove all its info | 661 | int migrate_platform_irqs(unsigned int cpu) |
631 | * from mt_info structure | 662 | { |
663 | int new_cpei_cpu; | ||
664 | irq_desc_t *desc = NULL; | ||
665 | cpumask_t mask; | ||
666 | int retval = 0; | ||
667 | |||
668 | /* | ||
669 | * dont permit CPEI target to removed. | ||
632 | */ | 670 | */ |
633 | if (last) | 671 | if (cpe_vector > 0 && is_cpu_cpei_target(cpu)) { |
634 | remove_from_mtinfo(cpu); | 672 | printk ("CPU (%d) is CPEI Target\n", cpu); |
673 | if (can_cpei_retarget()) { | ||
674 | /* | ||
675 | * Now re-target the CPEI to a different processor | ||
676 | */ | ||
677 | new_cpei_cpu = any_online_cpu(cpu_online_map); | ||
678 | mask = cpumask_of_cpu(new_cpei_cpu); | ||
679 | set_cpei_target_cpu(new_cpei_cpu); | ||
680 | desc = irq_descp(ia64_cpe_irq); | ||
681 | /* | ||
682 | * Switch for now, immediatly, we need to do fake intr | ||
683 | * as other interrupts, but need to study CPEI behaviour with | ||
684 | * polling before making changes. | ||
685 | */ | ||
686 | if (desc) { | ||
687 | desc->handler->disable(ia64_cpe_irq); | ||
688 | desc->handler->set_affinity(ia64_cpe_irq, mask); | ||
689 | desc->handler->enable(ia64_cpe_irq); | ||
690 | printk ("Re-targetting CPEI to cpu %d\n", new_cpei_cpu); | ||
691 | } | ||
692 | } | ||
693 | if (!desc) { | ||
694 | printk ("Unable to retarget CPEI, offline cpu [%d] failed\n", cpu); | ||
695 | retval = -EBUSY; | ||
696 | } | ||
697 | } | ||
698 | return retval; | ||
635 | } | 699 | } |
636 | 700 | ||
637 | extern void fixup_irqs(void); | ||
638 | /* must be called with cpucontrol mutex held */ | 701 | /* must be called with cpucontrol mutex held */ |
639 | int __cpu_disable(void) | 702 | int __cpu_disable(void) |
640 | { | 703 | { |
@@ -643,8 +706,17 @@ int __cpu_disable(void) | |||
643 | /* | 706 | /* |
644 | * dont permit boot processor for now | 707 | * dont permit boot processor for now |
645 | */ | 708 | */ |
646 | if (cpu == 0) | 709 | if (cpu == 0 && !bsp_remove_ok) { |
647 | return -EBUSY; | 710 | printk ("Your platform does not support removal of BSP\n"); |
711 | return (-EBUSY); | ||
712 | } | ||
713 | |||
714 | cpu_clear(cpu, cpu_online_map); | ||
715 | |||
716 | if (migrate_platform_irqs(cpu)) { | ||
717 | cpu_set(cpu, cpu_online_map); | ||
718 | return (-EBUSY); | ||
719 | } | ||
648 | 720 | ||
649 | remove_siblinginfo(cpu); | 721 | remove_siblinginfo(cpu); |
650 | cpu_clear(cpu, cpu_online_map); | 722 | cpu_clear(cpu, cpu_online_map); |
@@ -776,40 +848,6 @@ init_smp_config(void) | |||
776 | ia64_sal_strerror(sal_ret)); | 848 | ia64_sal_strerror(sal_ret)); |
777 | } | 849 | } |
778 | 850 | ||
779 | static inline int __devinit | ||
780 | check_for_mtinfo_index(void) | ||
781 | { | ||
782 | int i; | ||
783 | |||
784 | for_each_cpu(i) | ||
785 | if (!mt_info[i].valid) | ||
786 | return i; | ||
787 | |||
788 | return -1; | ||
789 | } | ||
790 | |||
791 | /* | ||
792 | * Search the mt_info to find out if this socket's cid/tid information is | ||
793 | * cached or not. If the socket exists, fill in the core_id and thread_id | ||
794 | * in cpuinfo | ||
795 | */ | ||
796 | static int __devinit | ||
797 | check_for_new_socket(__u16 logical_address, struct cpuinfo_ia64 *c) | ||
798 | { | ||
799 | int i; | ||
800 | __u32 sid = c->socket_id; | ||
801 | |||
802 | for_each_cpu(i) { | ||
803 | if (mt_info[i].valid && mt_info[i].proc_fixed_addr == logical_address | ||
804 | && mt_info[i].socket_id == sid) { | ||
805 | c->core_id = mt_info[i].core_id; | ||
806 | c->thread_id = mt_info[i].thread_id; | ||
807 | return 1; /* not a new socket */ | ||
808 | } | ||
809 | } | ||
810 | return 0; | ||
811 | } | ||
812 | |||
813 | /* | 851 | /* |
814 | * identify_siblings(cpu) gets called from identify_cpu. This populates the | 852 | * identify_siblings(cpu) gets called from identify_cpu. This populates the |
815 | * information related to logical execution units in per_cpu_data structure. | 853 | * information related to logical execution units in per_cpu_data structure. |
@@ -819,14 +857,12 @@ identify_siblings(struct cpuinfo_ia64 *c) | |||
819 | { | 857 | { |
820 | s64 status; | 858 | s64 status; |
821 | u16 pltid; | 859 | u16 pltid; |
822 | u64 proc_fixed_addr; | ||
823 | int count, i; | ||
824 | pal_logical_to_physical_t info; | 860 | pal_logical_to_physical_t info; |
825 | 861 | ||
826 | if (smp_num_cpucores == 1 && smp_num_siblings == 1) | 862 | if (smp_num_cpucores == 1 && smp_num_siblings == 1) |
827 | return; | 863 | return; |
828 | 864 | ||
829 | if ((status = ia64_pal_logical_to_phys(0, &info)) != PAL_STATUS_SUCCESS) { | 865 | if ((status = ia64_pal_logical_to_phys(-1, &info)) != PAL_STATUS_SUCCESS) { |
830 | printk(KERN_ERR "ia64_pal_logical_to_phys failed with %ld\n", | 866 | printk(KERN_ERR "ia64_pal_logical_to_phys failed with %ld\n", |
831 | status); | 867 | status); |
832 | return; | 868 | return; |
@@ -835,47 +871,12 @@ identify_siblings(struct cpuinfo_ia64 *c) | |||
835 | printk(KERN_ERR "ia64_sal_pltid failed with %ld\n", status); | 871 | printk(KERN_ERR "ia64_sal_pltid failed with %ld\n", status); |
836 | return; | 872 | return; |
837 | } | 873 | } |
838 | if ((status = ia64_pal_fixed_addr(&proc_fixed_addr)) != PAL_STATUS_SUCCESS) { | ||
839 | printk(KERN_ERR "ia64_pal_fixed_addr failed with %ld\n", status); | ||
840 | return; | ||
841 | } | ||
842 | 874 | ||
843 | c->socket_id = (pltid << 8) | info.overview_ppid; | 875 | c->socket_id = (pltid << 8) | info.overview_ppid; |
844 | c->cores_per_socket = info.overview_cpp; | 876 | c->cores_per_socket = info.overview_cpp; |
845 | c->threads_per_core = info.overview_tpc; | 877 | c->threads_per_core = info.overview_tpc; |
846 | count = c->num_log = info.overview_num_log; | 878 | c->num_log = info.overview_num_log; |
847 | |||
848 | /* If the thread and core id information is already cached, then | ||
849 | * we will simply update cpu_info and return. Otherwise, we will | ||
850 | * do the PAL calls and cache core and thread id's of all the siblings. | ||
851 | */ | ||
852 | if (check_for_new_socket(proc_fixed_addr, c)) | ||
853 | return; | ||
854 | |||
855 | for (i = 0; i < count; i++) { | ||
856 | int index; | ||
857 | |||
858 | if (i && (status = ia64_pal_logical_to_phys(i, &info)) | ||
859 | != PAL_STATUS_SUCCESS) { | ||
860 | printk(KERN_ERR "ia64_pal_logical_to_phys failed" | ||
861 | " with %ld\n", status); | ||
862 | return; | ||
863 | } | ||
864 | if (info.log2_la == proc_fixed_addr) { | ||
865 | c->core_id = info.log1_cid; | ||
866 | c->thread_id = info.log1_tid; | ||
867 | } | ||
868 | 879 | ||
869 | index = check_for_mtinfo_index(); | 880 | c->core_id = info.log1_cid; |
870 | /* We will not do the mt_info caching optimization in this case. | 881 | c->thread_id = info.log1_tid; |
871 | */ | ||
872 | if (index < 0) | ||
873 | continue; | ||
874 | |||
875 | mt_info[index].valid = 1; | ||
876 | mt_info[index].socket_id = c->socket_id; | ||
877 | mt_info[index].core_id = info.log1_cid; | ||
878 | mt_info[index].thread_id = info.log1_tid; | ||
879 | mt_info[index].proc_fixed_addr = info.log2_la; | ||
880 | } | ||
881 | } | 882 | } |
diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c index 307d01e15b2e..ac167436e936 100644 --- a/arch/ia64/kernel/time.c +++ b/arch/ia64/kernel/time.c | |||
@@ -32,7 +32,7 @@ | |||
32 | 32 | ||
33 | extern unsigned long wall_jiffies; | 33 | extern unsigned long wall_jiffies; |
34 | 34 | ||
35 | #define TIME_KEEPER_ID 0 /* smp_processor_id() of time-keeper */ | 35 | volatile int time_keeper_id = 0; /* smp_processor_id() of time-keeper */ |
36 | 36 | ||
37 | #ifdef CONFIG_IA64_DEBUG_IRQ | 37 | #ifdef CONFIG_IA64_DEBUG_IRQ |
38 | 38 | ||
@@ -71,7 +71,7 @@ timer_interrupt (int irq, void *dev_id, struct pt_regs *regs) | |||
71 | 71 | ||
72 | new_itm += local_cpu_data->itm_delta; | 72 | new_itm += local_cpu_data->itm_delta; |
73 | 73 | ||
74 | if (smp_processor_id() == TIME_KEEPER_ID) { | 74 | if (smp_processor_id() == time_keeper_id) { |
75 | /* | 75 | /* |
76 | * Here we are in the timer irq handler. We have irqs locally | 76 | * Here we are in the timer irq handler. We have irqs locally |
77 | * disabled, but we don't know if the timer_bh is running on | 77 | * disabled, but we don't know if the timer_bh is running on |
@@ -236,6 +236,11 @@ static struct irqaction timer_irqaction = { | |||
236 | .name = "timer" | 236 | .name = "timer" |
237 | }; | 237 | }; |
238 | 238 | ||
239 | void __devinit ia64_disable_timer(void) | ||
240 | { | ||
241 | ia64_set_itv(1 << 16); | ||
242 | } | ||
243 | |||
239 | void __init | 244 | void __init |
240 | time_init (void) | 245 | time_init (void) |
241 | { | 246 | { |
diff --git a/arch/ia64/kernel/topology.c b/arch/ia64/kernel/topology.c index 6e5eea19fa67..3b6fd798c4d6 100644 --- a/arch/ia64/kernel/topology.c +++ b/arch/ia64/kernel/topology.c | |||
@@ -36,7 +36,7 @@ int arch_register_cpu(int num) | |||
36 | parent = &sysfs_nodes[cpu_to_node(num)]; | 36 | parent = &sysfs_nodes[cpu_to_node(num)]; |
37 | #endif /* CONFIG_NUMA */ | 37 | #endif /* CONFIG_NUMA */ |
38 | 38 | ||
39 | #ifdef CONFIG_ACPI | 39 | #if defined (CONFIG_ACPI) && defined (CONFIG_HOTPLUG_CPU) |
40 | /* | 40 | /* |
41 | * If CPEI cannot be re-targetted, and this is | 41 | * If CPEI cannot be re-targetted, and this is |
42 | * CPEI target, then dont create the control file | 42 | * CPEI target, then dont create the control file |
diff --git a/arch/ia64/kernel/vmlinux.lds.S b/arch/ia64/kernel/vmlinux.lds.S index 73af6267d2ef..0b9e56dd7f05 100644 --- a/arch/ia64/kernel/vmlinux.lds.S +++ b/arch/ia64/kernel/vmlinux.lds.S | |||
@@ -70,34 +70,9 @@ SECTIONS | |||
70 | __stop___ex_table = .; | 70 | __stop___ex_table = .; |
71 | } | 71 | } |
72 | 72 | ||
73 | .data.patch.vtop : AT(ADDR(.data.patch.vtop) - LOAD_OFFSET) | ||
74 | { | ||
75 | __start___vtop_patchlist = .; | ||
76 | *(.data.patch.vtop) | ||
77 | __end___vtop_patchlist = .; | ||
78 | } | ||
79 | |||
80 | .data.patch.mckinley_e9 : AT(ADDR(.data.patch.mckinley_e9) - LOAD_OFFSET) | ||
81 | { | ||
82 | __start___mckinley_e9_bundles = .; | ||
83 | *(.data.patch.mckinley_e9) | ||
84 | __end___mckinley_e9_bundles = .; | ||
85 | } | ||
86 | |||
87 | /* Global data */ | 73 | /* Global data */ |
88 | _data = .; | 74 | _data = .; |
89 | 75 | ||
90 | #if defined(CONFIG_IA64_GENERIC) | ||
91 | /* Machine Vector */ | ||
92 | . = ALIGN(16); | ||
93 | .machvec : AT(ADDR(.machvec) - LOAD_OFFSET) | ||
94 | { | ||
95 | machvec_start = .; | ||
96 | *(.machvec) | ||
97 | machvec_end = .; | ||
98 | } | ||
99 | #endif | ||
100 | |||
101 | /* Unwind info & table: */ | 76 | /* Unwind info & table: */ |
102 | . = ALIGN(8); | 77 | . = ALIGN(8); |
103 | .IA_64.unwind_info : AT(ADDR(.IA_64.unwind_info) - LOAD_OFFSET) | 78 | .IA_64.unwind_info : AT(ADDR(.IA_64.unwind_info) - LOAD_OFFSET) |
@@ -154,6 +129,41 @@ SECTIONS | |||
154 | *(.initcall7.init) | 129 | *(.initcall7.init) |
155 | __initcall_end = .; | 130 | __initcall_end = .; |
156 | } | 131 | } |
132 | |||
133 | /* MCA table */ | ||
134 | . = ALIGN(16); | ||
135 | __mca_table : AT(ADDR(__mca_table) - LOAD_OFFSET) | ||
136 | { | ||
137 | __start___mca_table = .; | ||
138 | *(__mca_table) | ||
139 | __stop___mca_table = .; | ||
140 | } | ||
141 | |||
142 | .data.patch.vtop : AT(ADDR(.data.patch.vtop) - LOAD_OFFSET) | ||
143 | { | ||
144 | __start___vtop_patchlist = .; | ||
145 | *(.data.patch.vtop) | ||
146 | __end___vtop_patchlist = .; | ||
147 | } | ||
148 | |||
149 | .data.patch.mckinley_e9 : AT(ADDR(.data.patch.mckinley_e9) - LOAD_OFFSET) | ||
150 | { | ||
151 | __start___mckinley_e9_bundles = .; | ||
152 | *(.data.patch.mckinley_e9) | ||
153 | __end___mckinley_e9_bundles = .; | ||
154 | } | ||
155 | |||
156 | #if defined(CONFIG_IA64_GENERIC) | ||
157 | /* Machine Vector */ | ||
158 | . = ALIGN(16); | ||
159 | .machvec : AT(ADDR(.machvec) - LOAD_OFFSET) | ||
160 | { | ||
161 | machvec_start = .; | ||
162 | *(.machvec) | ||
163 | machvec_end = .; | ||
164 | } | ||
165 | #endif | ||
166 | |||
157 | __con_initcall_start = .; | 167 | __con_initcall_start = .; |
158 | .con_initcall.init : AT(ADDR(.con_initcall.init) - LOAD_OFFSET) | 168 | .con_initcall.init : AT(ADDR(.con_initcall.init) - LOAD_OFFSET) |
159 | { *(.con_initcall.init) } | 169 | { *(.con_initcall.init) } |
diff --git a/arch/ia64/mm/contig.c b/arch/ia64/mm/contig.c index acaaec4e4681..84fd1c14c8a9 100644 --- a/arch/ia64/mm/contig.c +++ b/arch/ia64/mm/contig.c | |||
@@ -97,7 +97,7 @@ find_max_pfn (unsigned long start, unsigned long end, void *arg) | |||
97 | * Find a place to put the bootmap and return its starting address in | 97 | * Find a place to put the bootmap and return its starting address in |
98 | * bootmap_start. This address must be page-aligned. | 98 | * bootmap_start. This address must be page-aligned. |
99 | */ | 99 | */ |
100 | int | 100 | static int __init |
101 | find_bootmap_location (unsigned long start, unsigned long end, void *arg) | 101 | find_bootmap_location (unsigned long start, unsigned long end, void *arg) |
102 | { | 102 | { |
103 | unsigned long needed = *(unsigned long *)arg; | 103 | unsigned long needed = *(unsigned long *)arg; |
@@ -141,7 +141,7 @@ find_bootmap_location (unsigned long start, unsigned long end, void *arg) | |||
141 | * Walk the EFI memory map and find usable memory for the system, taking | 141 | * Walk the EFI memory map and find usable memory for the system, taking |
142 | * into account reserved areas. | 142 | * into account reserved areas. |
143 | */ | 143 | */ |
144 | void | 144 | void __init |
145 | find_memory (void) | 145 | find_memory (void) |
146 | { | 146 | { |
147 | unsigned long bootmap_size; | 147 | unsigned long bootmap_size; |
@@ -176,18 +176,20 @@ find_memory (void) | |||
176 | * | 176 | * |
177 | * Allocate and setup per-cpu data areas. | 177 | * Allocate and setup per-cpu data areas. |
178 | */ | 178 | */ |
179 | void * | 179 | void * __cpuinit |
180 | per_cpu_init (void) | 180 | per_cpu_init (void) |
181 | { | 181 | { |
182 | void *cpu_data; | 182 | void *cpu_data; |
183 | int cpu; | 183 | int cpu; |
184 | static int first_time=1; | ||
184 | 185 | ||
185 | /* | 186 | /* |
186 | * get_free_pages() cannot be used before cpu_init() done. BSP | 187 | * get_free_pages() cannot be used before cpu_init() done. BSP |
187 | * allocates "NR_CPUS" pages for all CPUs to avoid that AP calls | 188 | * allocates "NR_CPUS" pages for all CPUs to avoid that AP calls |
188 | * get_zeroed_page(). | 189 | * get_zeroed_page(). |
189 | */ | 190 | */ |
190 | if (smp_processor_id() == 0) { | 191 | if (first_time) { |
192 | first_time=0; | ||
191 | cpu_data = __alloc_bootmem(PERCPU_PAGE_SIZE * NR_CPUS, | 193 | cpu_data = __alloc_bootmem(PERCPU_PAGE_SIZE * NR_CPUS, |
192 | PERCPU_PAGE_SIZE, __pa(MAX_DMA_ADDRESS)); | 194 | PERCPU_PAGE_SIZE, __pa(MAX_DMA_ADDRESS)); |
193 | for (cpu = 0; cpu < NR_CPUS; cpu++) { | 195 | for (cpu = 0; cpu < NR_CPUS; cpu++) { |
@@ -226,7 +228,7 @@ count_dma_pages (u64 start, u64 end, void *arg) | |||
226 | * Set up the page tables. | 228 | * Set up the page tables. |
227 | */ | 229 | */ |
228 | 230 | ||
229 | void | 231 | void __init |
230 | paging_init (void) | 232 | paging_init (void) |
231 | { | 233 | { |
232 | unsigned long max_dma; | 234 | unsigned long max_dma; |
diff --git a/arch/ia64/mm/discontig.c b/arch/ia64/mm/discontig.c index c87d6d1d5813..2f5e44862e91 100644 --- a/arch/ia64/mm/discontig.c +++ b/arch/ia64/mm/discontig.c | |||
@@ -525,15 +525,20 @@ void __init find_memory(void) | |||
525 | * find_pernode_space() does most of this already, we just need to set | 525 | * find_pernode_space() does most of this already, we just need to set |
526 | * local_per_cpu_offset | 526 | * local_per_cpu_offset |
527 | */ | 527 | */ |
528 | void *per_cpu_init(void) | 528 | void __cpuinit *per_cpu_init(void) |
529 | { | 529 | { |
530 | int cpu; | 530 | int cpu; |
531 | static int first_time = 1; | ||
532 | |||
531 | 533 | ||
532 | if (smp_processor_id() != 0) | 534 | if (smp_processor_id() != 0) |
533 | return __per_cpu_start + __per_cpu_offset[smp_processor_id()]; | 535 | return __per_cpu_start + __per_cpu_offset[smp_processor_id()]; |
534 | 536 | ||
535 | for (cpu = 0; cpu < NR_CPUS; cpu++) | 537 | if (first_time) { |
536 | per_cpu(local_per_cpu_offset, cpu) = __per_cpu_offset[cpu]; | 538 | first_time = 0; |
539 | for (cpu = 0; cpu < NR_CPUS; cpu++) | ||
540 | per_cpu(local_per_cpu_offset, cpu) = __per_cpu_offset[cpu]; | ||
541 | } | ||
537 | 542 | ||
538 | return __per_cpu_start + __per_cpu_offset[smp_processor_id()]; | 543 | return __per_cpu_start + __per_cpu_offset[smp_processor_id()]; |
539 | } | 544 | } |
diff --git a/arch/ia64/mm/hugetlbpage.c b/arch/ia64/mm/hugetlbpage.c index 2d13889d0a99..8d506710fdbd 100644 --- a/arch/ia64/mm/hugetlbpage.c +++ b/arch/ia64/mm/hugetlbpage.c | |||
@@ -68,9 +68,10 @@ huge_pte_offset (struct mm_struct *mm, unsigned long addr) | |||
68 | #define mk_pte_huge(entry) { pte_val(entry) |= _PAGE_P; } | 68 | #define mk_pte_huge(entry) { pte_val(entry) |= _PAGE_P; } |
69 | 69 | ||
70 | /* | 70 | /* |
71 | * This function checks for proper alignment of input addr and len parameters. | 71 | * Don't actually need to do any preparation, but need to make sure |
72 | * the address is in the right region. | ||
72 | */ | 73 | */ |
73 | int is_aligned_hugepage_range(unsigned long addr, unsigned long len) | 74 | int prepare_hugepage_range(unsigned long addr, unsigned long len) |
74 | { | 75 | { |
75 | if (len & ~HPAGE_MASK) | 76 | if (len & ~HPAGE_MASK) |
76 | return -EINVAL; | 77 | return -EINVAL; |
@@ -112,8 +113,7 @@ void hugetlb_free_pgd_range(struct mmu_gather **tlb, | |||
112 | unsigned long floor, unsigned long ceiling) | 113 | unsigned long floor, unsigned long ceiling) |
113 | { | 114 | { |
114 | /* | 115 | /* |
115 | * This is called only when is_hugepage_only_range(addr,), | 116 | * This is called to free hugetlb page tables. |
116 | * and it follows that is_hugepage_only_range(end,) also. | ||
117 | * | 117 | * |
118 | * The offset of these addresses from the base of the hugetlb | 118 | * The offset of these addresses from the base of the hugetlb |
119 | * region must be scaled down by HPAGE_SIZE/PAGE_SIZE so that | 119 | * region must be scaled down by HPAGE_SIZE/PAGE_SIZE so that |
@@ -125,9 +125,9 @@ void hugetlb_free_pgd_range(struct mmu_gather **tlb, | |||
125 | 125 | ||
126 | addr = htlbpage_to_page(addr); | 126 | addr = htlbpage_to_page(addr); |
127 | end = htlbpage_to_page(end); | 127 | end = htlbpage_to_page(end); |
128 | if (is_hugepage_only_range(tlb->mm, floor, HPAGE_SIZE)) | 128 | if (REGION_NUMBER(floor) == RGN_HPAGE) |
129 | floor = htlbpage_to_page(floor); | 129 | floor = htlbpage_to_page(floor); |
130 | if (is_hugepage_only_range(tlb->mm, ceiling, HPAGE_SIZE)) | 130 | if (REGION_NUMBER(ceiling) == RGN_HPAGE) |
131 | ceiling = htlbpage_to_page(ceiling); | 131 | ceiling = htlbpage_to_page(ceiling); |
132 | 132 | ||
133 | free_pgd_range(tlb, addr, end, floor, ceiling); | 133 | free_pgd_range(tlb, addr, end, floor, ceiling); |
diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c index b38b6d213c15..ff4f31fcd330 100644 --- a/arch/ia64/mm/init.c +++ b/arch/ia64/mm/init.c | |||
@@ -197,7 +197,7 @@ free_initmem (void) | |||
197 | eaddr = (unsigned long) ia64_imva(__init_end); | 197 | eaddr = (unsigned long) ia64_imva(__init_end); |
198 | while (addr < eaddr) { | 198 | while (addr < eaddr) { |
199 | ClearPageReserved(virt_to_page(addr)); | 199 | ClearPageReserved(virt_to_page(addr)); |
200 | set_page_count(virt_to_page(addr), 1); | 200 | init_page_count(virt_to_page(addr)); |
201 | free_page(addr); | 201 | free_page(addr); |
202 | ++totalram_pages; | 202 | ++totalram_pages; |
203 | addr += PAGE_SIZE; | 203 | addr += PAGE_SIZE; |
@@ -206,7 +206,7 @@ free_initmem (void) | |||
206 | (__init_end - __init_begin) >> 10); | 206 | (__init_end - __init_begin) >> 10); |
207 | } | 207 | } |
208 | 208 | ||
209 | void | 209 | void __init |
210 | free_initrd_mem (unsigned long start, unsigned long end) | 210 | free_initrd_mem (unsigned long start, unsigned long end) |
211 | { | 211 | { |
212 | struct page *page; | 212 | struct page *page; |
@@ -252,7 +252,7 @@ free_initrd_mem (unsigned long start, unsigned long end) | |||
252 | continue; | 252 | continue; |
253 | page = virt_to_page(start); | 253 | page = virt_to_page(start); |
254 | ClearPageReserved(page); | 254 | ClearPageReserved(page); |
255 | set_page_count(page, 1); | 255 | init_page_count(page); |
256 | free_page(start); | 256 | free_page(start); |
257 | ++totalram_pages; | 257 | ++totalram_pages; |
258 | } | 258 | } |
@@ -261,7 +261,7 @@ free_initrd_mem (unsigned long start, unsigned long end) | |||
261 | /* | 261 | /* |
262 | * This installs a clean page in the kernel's page table. | 262 | * This installs a clean page in the kernel's page table. |
263 | */ | 263 | */ |
264 | struct page * | 264 | static struct page * __init |
265 | put_kernel_page (struct page *page, unsigned long address, pgprot_t pgprot) | 265 | put_kernel_page (struct page *page, unsigned long address, pgprot_t pgprot) |
266 | { | 266 | { |
267 | pgd_t *pgd; | 267 | pgd_t *pgd; |
@@ -294,7 +294,7 @@ put_kernel_page (struct page *page, unsigned long address, pgprot_t pgprot) | |||
294 | return page; | 294 | return page; |
295 | } | 295 | } |
296 | 296 | ||
297 | static void | 297 | static void __init |
298 | setup_gate (void) | 298 | setup_gate (void) |
299 | { | 299 | { |
300 | struct page *page; | 300 | struct page *page; |
@@ -411,7 +411,7 @@ ia64_mmu_init (void *my_cpu_data) | |||
411 | 411 | ||
412 | #ifdef CONFIG_VIRTUAL_MEM_MAP | 412 | #ifdef CONFIG_VIRTUAL_MEM_MAP |
413 | 413 | ||
414 | int | 414 | int __init |
415 | create_mem_map_page_table (u64 start, u64 end, void *arg) | 415 | create_mem_map_page_table (u64 start, u64 end, void *arg) |
416 | { | 416 | { |
417 | unsigned long address, start_page, end_page; | 417 | unsigned long address, start_page, end_page; |
@@ -519,7 +519,7 @@ ia64_pfn_valid (unsigned long pfn) | |||
519 | } | 519 | } |
520 | EXPORT_SYMBOL(ia64_pfn_valid); | 520 | EXPORT_SYMBOL(ia64_pfn_valid); |
521 | 521 | ||
522 | int | 522 | int __init |
523 | find_largest_hole (u64 start, u64 end, void *arg) | 523 | find_largest_hole (u64 start, u64 end, void *arg) |
524 | { | 524 | { |
525 | u64 *max_gap = arg; | 525 | u64 *max_gap = arg; |
@@ -535,7 +535,7 @@ find_largest_hole (u64 start, u64 end, void *arg) | |||
535 | } | 535 | } |
536 | #endif /* CONFIG_VIRTUAL_MEM_MAP */ | 536 | #endif /* CONFIG_VIRTUAL_MEM_MAP */ |
537 | 537 | ||
538 | static int | 538 | static int __init |
539 | count_reserved_pages (u64 start, u64 end, void *arg) | 539 | count_reserved_pages (u64 start, u64 end, void *arg) |
540 | { | 540 | { |
541 | unsigned long num_reserved = 0; | 541 | unsigned long num_reserved = 0; |
@@ -556,7 +556,7 @@ count_reserved_pages (u64 start, u64 end, void *arg) | |||
556 | * purposes. | 556 | * purposes. |
557 | */ | 557 | */ |
558 | 558 | ||
559 | static int nolwsys; | 559 | static int nolwsys __initdata; |
560 | 560 | ||
561 | static int __init | 561 | static int __init |
562 | nolwsys_setup (char *s) | 562 | nolwsys_setup (char *s) |
@@ -567,7 +567,7 @@ nolwsys_setup (char *s) | |||
567 | 567 | ||
568 | __setup("nolwsys", nolwsys_setup); | 568 | __setup("nolwsys", nolwsys_setup); |
569 | 569 | ||
570 | void | 570 | void __init |
571 | mem_init (void) | 571 | mem_init (void) |
572 | { | 572 | { |
573 | long reserved_pages, codesize, datasize, initsize; | 573 | long reserved_pages, codesize, datasize, initsize; |
@@ -640,7 +640,7 @@ mem_init (void) | |||
640 | void online_page(struct page *page) | 640 | void online_page(struct page *page) |
641 | { | 641 | { |
642 | ClearPageReserved(page); | 642 | ClearPageReserved(page); |
643 | set_page_count(page, 1); | 643 | init_page_count(page); |
644 | __free_page(page); | 644 | __free_page(page); |
645 | totalram_pages++; | 645 | totalram_pages++; |
646 | num_physpages++; | 646 | num_physpages++; |
diff --git a/arch/ia64/sn/kernel/Makefile b/arch/ia64/sn/kernel/Makefile index 3e9b4eea7418..ab9c48c88012 100644 --- a/arch/ia64/sn/kernel/Makefile +++ b/arch/ia64/sn/kernel/Makefile | |||
@@ -10,7 +10,8 @@ | |||
10 | CPPFLAGS += -I$(srctree)/arch/ia64/sn/include | 10 | CPPFLAGS += -I$(srctree)/arch/ia64/sn/include |
11 | 11 | ||
12 | obj-y += setup.o bte.o bte_error.o irq.o mca.o idle.o \ | 12 | obj-y += setup.o bte.o bte_error.o irq.o mca.o idle.o \ |
13 | huberror.o io_init.o iomv.o klconflib.o sn2/ | 13 | huberror.o io_init.o iomv.o klconflib.o pio_phys.o \ |
14 | sn2/ | ||
14 | obj-$(CONFIG_IA64_GENERIC) += machvec.o | 15 | obj-$(CONFIG_IA64_GENERIC) += machvec.o |
15 | obj-$(CONFIG_SGI_TIOCX) += tiocx.o | 16 | obj-$(CONFIG_SGI_TIOCX) += tiocx.o |
16 | obj-$(CONFIG_IA64_SGI_SN_XP) += xp.o | 17 | obj-$(CONFIG_IA64_SGI_SN_XP) += xp.o |
diff --git a/arch/ia64/sn/kernel/bte.c b/arch/ia64/sn/kernel/bte.c index 1f11db470d90..e952ef4f6d91 100644 --- a/arch/ia64/sn/kernel/bte.c +++ b/arch/ia64/sn/kernel/bte.c | |||
@@ -36,7 +36,7 @@ static struct bteinfo_s *bte_if_on_node(nasid_t nasid, int interface) | |||
36 | nodepda_t *tmp_nodepda; | 36 | nodepda_t *tmp_nodepda; |
37 | 37 | ||
38 | if (nasid_to_cnodeid(nasid) == -1) | 38 | if (nasid_to_cnodeid(nasid) == -1) |
39 | return (struct bteinfo_s *)NULL;; | 39 | return (struct bteinfo_s *)NULL; |
40 | 40 | ||
41 | tmp_nodepda = NODEPDA(nasid_to_cnodeid(nasid)); | 41 | tmp_nodepda = NODEPDA(nasid_to_cnodeid(nasid)); |
42 | return &tmp_nodepda->bte_if[interface]; | 42 | return &tmp_nodepda->bte_if[interface]; |
diff --git a/arch/ia64/sn/kernel/io_init.c b/arch/ia64/sn/kernel/io_init.c index dfb3f2902379..5101ac462643 100644 --- a/arch/ia64/sn/kernel/io_init.c +++ b/arch/ia64/sn/kernel/io_init.c | |||
@@ -13,6 +13,8 @@ | |||
13 | #include <asm/sn/sn_feature_sets.h> | 13 | #include <asm/sn/sn_feature_sets.h> |
14 | #include <asm/sn/geo.h> | 14 | #include <asm/sn/geo.h> |
15 | #include <asm/sn/io.h> | 15 | #include <asm/sn/io.h> |
16 | #include <asm/sn/l1.h> | ||
17 | #include <asm/sn/module.h> | ||
16 | #include <asm/sn/pcibr_provider.h> | 18 | #include <asm/sn/pcibr_provider.h> |
17 | #include <asm/sn/pcibus_provider_defs.h> | 19 | #include <asm/sn/pcibus_provider_defs.h> |
18 | #include <asm/sn/pcidev.h> | 20 | #include <asm/sn/pcidev.h> |
@@ -710,9 +712,36 @@ cnodeid_get_geoid(cnodeid_t cnode) | |||
710 | return hubdev->hdi_geoid; | 712 | return hubdev->hdi_geoid; |
711 | } | 713 | } |
712 | 714 | ||
715 | void sn_generate_path(struct pci_bus *pci_bus, char *address) | ||
716 | { | ||
717 | nasid_t nasid; | ||
718 | cnodeid_t cnode; | ||
719 | geoid_t geoid; | ||
720 | moduleid_t moduleid; | ||
721 | u16 bricktype; | ||
722 | |||
723 | nasid = NASID_GET(SN_PCIBUS_BUSSOFT(pci_bus)->bs_base); | ||
724 | cnode = nasid_to_cnodeid(nasid); | ||
725 | geoid = cnodeid_get_geoid(cnode); | ||
726 | moduleid = geo_module(geoid); | ||
727 | |||
728 | sprintf(address, "module_%c%c%c%c%.2d", | ||
729 | '0'+RACK_GET_CLASS(MODULE_GET_RACK(moduleid)), | ||
730 | '0'+RACK_GET_GROUP(MODULE_GET_RACK(moduleid)), | ||
731 | '0'+RACK_GET_NUM(MODULE_GET_RACK(moduleid)), | ||
732 | MODULE_GET_BTCHAR(moduleid), MODULE_GET_BPOS(moduleid)); | ||
733 | |||
734 | /* Tollhouse requires slot id to be displayed */ | ||
735 | bricktype = MODULE_GET_BTYPE(moduleid); | ||
736 | if ((bricktype == L1_BRICKTYPE_191010) || | ||
737 | (bricktype == L1_BRICKTYPE_1932)) | ||
738 | sprintf(address, "%s^%d", address, geo_slot(geoid)); | ||
739 | } | ||
740 | |||
713 | subsys_initcall(sn_pci_init); | 741 | subsys_initcall(sn_pci_init); |
714 | EXPORT_SYMBOL(sn_pci_fixup_slot); | 742 | EXPORT_SYMBOL(sn_pci_fixup_slot); |
715 | EXPORT_SYMBOL(sn_pci_unfixup_slot); | 743 | EXPORT_SYMBOL(sn_pci_unfixup_slot); |
716 | EXPORT_SYMBOL(sn_pci_controller_fixup); | 744 | EXPORT_SYMBOL(sn_pci_controller_fixup); |
717 | EXPORT_SYMBOL(sn_bus_store_sysdata); | 745 | EXPORT_SYMBOL(sn_bus_store_sysdata); |
718 | EXPORT_SYMBOL(sn_bus_free_sysdata); | 746 | EXPORT_SYMBOL(sn_bus_free_sysdata); |
747 | EXPORT_SYMBOL(sn_generate_path); | ||
diff --git a/arch/ia64/sn/kernel/irq.c b/arch/ia64/sn/kernel/irq.c index c373113d073a..c265e02f5036 100644 --- a/arch/ia64/sn/kernel/irq.c +++ b/arch/ia64/sn/kernel/irq.c | |||
@@ -350,9 +350,6 @@ static void force_interrupt(int irq) | |||
350 | static void sn_check_intr(int irq, struct sn_irq_info *sn_irq_info) | 350 | static void sn_check_intr(int irq, struct sn_irq_info *sn_irq_info) |
351 | { | 351 | { |
352 | u64 regval; | 352 | u64 regval; |
353 | int irr_reg_num; | ||
354 | int irr_bit; | ||
355 | u64 irr_reg; | ||
356 | struct pcidev_info *pcidev_info; | 353 | struct pcidev_info *pcidev_info; |
357 | struct pcibus_info *pcibus_info; | 354 | struct pcibus_info *pcibus_info; |
358 | 355 | ||
@@ -373,23 +370,7 @@ static void sn_check_intr(int irq, struct sn_irq_info *sn_irq_info) | |||
373 | pdi_pcibus_info; | 370 | pdi_pcibus_info; |
374 | regval = pcireg_intr_status_get(pcibus_info); | 371 | regval = pcireg_intr_status_get(pcibus_info); |
375 | 372 | ||
376 | irr_reg_num = irq_to_vector(irq) / 64; | 373 | if (!ia64_get_irr(irq_to_vector(irq))) { |
377 | irr_bit = irq_to_vector(irq) % 64; | ||
378 | switch (irr_reg_num) { | ||
379 | case 0: | ||
380 | irr_reg = ia64_getreg(_IA64_REG_CR_IRR0); | ||
381 | break; | ||
382 | case 1: | ||
383 | irr_reg = ia64_getreg(_IA64_REG_CR_IRR1); | ||
384 | break; | ||
385 | case 2: | ||
386 | irr_reg = ia64_getreg(_IA64_REG_CR_IRR2); | ||
387 | break; | ||
388 | case 3: | ||
389 | irr_reg = ia64_getreg(_IA64_REG_CR_IRR3); | ||
390 | break; | ||
391 | } | ||
392 | if (!test_bit(irr_bit, &irr_reg)) { | ||
393 | if (!test_bit(irq, pda->sn_in_service_ivecs)) { | 374 | if (!test_bit(irq, pda->sn_in_service_ivecs)) { |
394 | regval &= 0xff; | 375 | regval &= 0xff; |
395 | if (sn_irq_info->irq_int_bit & regval & | 376 | if (sn_irq_info->irq_int_bit & regval & |
diff --git a/arch/ia64/sn/kernel/pio_phys.S b/arch/ia64/sn/kernel/pio_phys.S new file mode 100644 index 000000000000..3c7d48d6ecb8 --- /dev/null +++ b/arch/ia64/sn/kernel/pio_phys.S | |||
@@ -0,0 +1,71 @@ | |||
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) 2000-2005 Silicon Graphics, Inc. All rights reserved. | ||
7 | * | ||
8 | * This file contains macros used to access MMR registers via | ||
9 | * uncached physical addresses. | ||
10 | * pio_phys_read_mmr - read an MMR | ||
11 | * pio_phys_write_mmr - write an MMR | ||
12 | * pio_atomic_phys_write_mmrs - atomically write 1 or 2 MMRs with psr.ic=0 | ||
13 | * Second MMR will be skipped if address is NULL | ||
14 | * | ||
15 | * Addresses passed to these routines should be uncached physical addresses | ||
16 | * ie., 0x80000.... | ||
17 | */ | ||
18 | |||
19 | |||
20 | |||
21 | #include <asm/asmmacro.h> | ||
22 | #include <asm/page.h> | ||
23 | |||
24 | GLOBAL_ENTRY(pio_phys_read_mmr) | ||
25 | .prologue | ||
26 | .regstk 1,0,0,0 | ||
27 | .body | ||
28 | mov r2=psr | ||
29 | rsm psr.i | psr.dt | ||
30 | ;; | ||
31 | srlz.d | ||
32 | ld8.acq r8=[r32] | ||
33 | ;; | ||
34 | mov psr.l=r2;; | ||
35 | srlz.d | ||
36 | br.ret.sptk.many rp | ||
37 | END(pio_phys_read_mmr) | ||
38 | |||
39 | GLOBAL_ENTRY(pio_phys_write_mmr) | ||
40 | .prologue | ||
41 | .regstk 2,0,0,0 | ||
42 | .body | ||
43 | mov r2=psr | ||
44 | rsm psr.i | psr.dt | ||
45 | ;; | ||
46 | srlz.d | ||
47 | st8.rel [r32]=r33 | ||
48 | ;; | ||
49 | mov psr.l=r2;; | ||
50 | srlz.d | ||
51 | br.ret.sptk.many rp | ||
52 | END(pio_phys_write_mmr) | ||
53 | |||
54 | GLOBAL_ENTRY(pio_atomic_phys_write_mmrs) | ||
55 | .prologue | ||
56 | .regstk 4,0,0,0 | ||
57 | .body | ||
58 | mov r2=psr | ||
59 | cmp.ne p9,p0=r34,r0; | ||
60 | rsm psr.i | psr.dt | psr.ic | ||
61 | ;; | ||
62 | srlz.d | ||
63 | st8.rel [r32]=r33 | ||
64 | (p9) st8.rel [r34]=r35 | ||
65 | ;; | ||
66 | mov psr.l=r2;; | ||
67 | srlz.d | ||
68 | br.ret.sptk.many rp | ||
69 | END(pio_atomic_phys_write_mmrs) | ||
70 | |||
71 | |||
diff --git a/arch/ia64/sn/kernel/setup.c b/arch/ia64/sn/kernel/setup.c index 5b84836c2171..8b6d5c844708 100644 --- a/arch/ia64/sn/kernel/setup.c +++ b/arch/ia64/sn/kernel/setup.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) 1999,2001-2005 Silicon Graphics, Inc. All rights reserved. | 6 | * Copyright (C) 1999,2001-2006 Silicon Graphics, Inc. All rights reserved. |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <linux/config.h> | 9 | #include <linux/config.h> |
@@ -498,6 +498,7 @@ void __init sn_setup(char **cmdline_p) | |||
498 | * for sn. | 498 | * for sn. |
499 | */ | 499 | */ |
500 | pm_power_off = ia64_sn_power_down; | 500 | pm_power_off = ia64_sn_power_down; |
501 | current->thread.flags |= IA64_THREAD_MIGRATION; | ||
501 | } | 502 | } |
502 | 503 | ||
503 | /** | 504 | /** |
@@ -660,7 +661,8 @@ void __init sn_cpu_init(void) | |||
660 | SH2_PIO_WRITE_STATUS_1, SH2_PIO_WRITE_STATUS_3}; | 661 | SH2_PIO_WRITE_STATUS_1, SH2_PIO_WRITE_STATUS_3}; |
661 | u64 *pio; | 662 | u64 *pio; |
662 | pio = is_shub1() ? pio1 : pio2; | 663 | pio = is_shub1() ? pio1 : pio2; |
663 | pda->pio_write_status_addr = (volatile unsigned long *) LOCAL_MMR_ADDR(pio[slice]); | 664 | pda->pio_write_status_addr = |
665 | (volatile unsigned long *)GLOBAL_MMR_ADDR(nasid, pio[slice]); | ||
664 | pda->pio_write_status_val = is_shub1() ? SH_PIO_WRITE_STATUS_PENDING_WRITE_COUNT_MASK : 0; | 666 | pda->pio_write_status_val = is_shub1() ? SH_PIO_WRITE_STATUS_PENDING_WRITE_COUNT_MASK : 0; |
665 | } | 667 | } |
666 | 668 | ||
diff --git a/arch/ia64/sn/kernel/sn2/sn2_smp.c b/arch/ia64/sn/kernel/sn2/sn2_smp.c index b2e1e746b47f..d9d306c79f2d 100644 --- a/arch/ia64/sn/kernel/sn2/sn2_smp.c +++ b/arch/ia64/sn/kernel/sn2/sn2_smp.c | |||
@@ -93,6 +93,27 @@ static inline unsigned long wait_piowc(void) | |||
93 | return (ws & SH_PIO_WRITE_STATUS_WRITE_DEADLOCK_MASK) != 0; | 93 | return (ws & SH_PIO_WRITE_STATUS_WRITE_DEADLOCK_MASK) != 0; |
94 | } | 94 | } |
95 | 95 | ||
96 | /** | ||
97 | * sn_migrate - SN-specific task migration actions | ||
98 | * @task: Task being migrated to new CPU | ||
99 | * | ||
100 | * SN2 PIO writes from separate CPUs are not guaranteed to arrive in order. | ||
101 | * Context switching user threads which have memory-mapped MMIO may cause | ||
102 | * PIOs to issue from seperate CPUs, thus the PIO writes must be drained | ||
103 | * from the previous CPU's Shub before execution resumes on the new CPU. | ||
104 | */ | ||
105 | void sn_migrate(struct task_struct *task) | ||
106 | { | ||
107 | pda_t *last_pda = pdacpu(task_thread_info(task)->last_cpu); | ||
108 | volatile unsigned long *adr = last_pda->pio_write_status_addr; | ||
109 | unsigned long val = last_pda->pio_write_status_val; | ||
110 | |||
111 | /* Drain PIO writes from old CPU's Shub */ | ||
112 | while (unlikely((*adr & SH_PIO_WRITE_STATUS_PENDING_WRITE_COUNT_MASK) | ||
113 | != val)) | ||
114 | cpu_relax(); | ||
115 | } | ||
116 | |||
96 | void sn_tlb_migrate_finish(struct mm_struct *mm) | 117 | void sn_tlb_migrate_finish(struct mm_struct *mm) |
97 | { | 118 | { |
98 | /* flush_tlb_mm is inefficient if more than 1 users of mm */ | 119 | /* flush_tlb_mm is inefficient if more than 1 users of mm */ |
diff --git a/arch/ia64/sn/kernel/tiocx.c b/arch/ia64/sn/kernel/tiocx.c index 99cb28e74295..feaf1a6e8101 100644 --- a/arch/ia64/sn/kernel/tiocx.c +++ b/arch/ia64/sn/kernel/tiocx.c | |||
@@ -369,9 +369,15 @@ static void tio_corelet_reset(nasid_t nasid, int corelet) | |||
369 | 369 | ||
370 | static int is_fpga_tio(int nasid, int *bt) | 370 | static int is_fpga_tio(int nasid, int *bt) |
371 | { | 371 | { |
372 | int ioboard_type; | 372 | u16 ioboard_type; |
373 | s64 rc; | ||
373 | 374 | ||
374 | ioboard_type = ia64_sn_sysctl_ioboard_get(nasid); | 375 | rc = ia64_sn_sysctl_ioboard_get(nasid, &ioboard_type); |
376 | if (rc) { | ||
377 | printk(KERN_WARNING "ia64_sn_sysctl_ioboard_get failed: %ld\n", | ||
378 | rc); | ||
379 | return 0; | ||
380 | } | ||
375 | 381 | ||
376 | switch (ioboard_type) { | 382 | switch (ioboard_type) { |
377 | case L1_BRICKTYPE_SA: | 383 | case L1_BRICKTYPE_SA: |
diff --git a/arch/ia64/sn/kernel/xpc_channel.c b/arch/ia64/sn/kernel/xpc_channel.c index cdf6856ce089..d0abddd9ffe6 100644 --- a/arch/ia64/sn/kernel/xpc_channel.c +++ b/arch/ia64/sn/kernel/xpc_channel.c | |||
@@ -21,7 +21,6 @@ | |||
21 | #include <linux/sched.h> | 21 | #include <linux/sched.h> |
22 | #include <linux/cache.h> | 22 | #include <linux/cache.h> |
23 | #include <linux/interrupt.h> | 23 | #include <linux/interrupt.h> |
24 | #include <linux/slab.h> | ||
25 | #include <linux/mutex.h> | 24 | #include <linux/mutex.h> |
26 | #include <linux/completion.h> | 25 | #include <linux/completion.h> |
27 | #include <asm/sn/bte.h> | 26 | #include <asm/sn/bte.h> |
@@ -30,6 +29,31 @@ | |||
30 | 29 | ||
31 | 30 | ||
32 | /* | 31 | /* |
32 | * Guarantee that the kzalloc'd memory is cacheline aligned. | ||
33 | */ | ||
34 | static void * | ||
35 | xpc_kzalloc_cacheline_aligned(size_t size, gfp_t flags, void **base) | ||
36 | { | ||
37 | /* see if kzalloc will give us cachline aligned memory by default */ | ||
38 | *base = kzalloc(size, flags); | ||
39 | if (*base == NULL) { | ||
40 | return NULL; | ||
41 | } | ||
42 | if ((u64) *base == L1_CACHE_ALIGN((u64) *base)) { | ||
43 | return *base; | ||
44 | } | ||
45 | kfree(*base); | ||
46 | |||
47 | /* nope, we'll have to do it ourselves */ | ||
48 | *base = kzalloc(size + L1_CACHE_BYTES, flags); | ||
49 | if (*base == NULL) { | ||
50 | return NULL; | ||
51 | } | ||
52 | return (void *) L1_CACHE_ALIGN((u64) *base); | ||
53 | } | ||
54 | |||
55 | |||
56 | /* | ||
33 | * Set up the initial values for the XPartition Communication channels. | 57 | * Set up the initial values for the XPartition Communication channels. |
34 | */ | 58 | */ |
35 | static void | 59 | static void |
@@ -93,20 +117,19 @@ xpc_setup_infrastructure(struct xpc_partition *part) | |||
93 | * Allocate all of the channel structures as a contiguous chunk of | 117 | * Allocate all of the channel structures as a contiguous chunk of |
94 | * memory. | 118 | * memory. |
95 | */ | 119 | */ |
96 | part->channels = kmalloc(sizeof(struct xpc_channel) * XPC_NCHANNELS, | 120 | part->channels = kzalloc(sizeof(struct xpc_channel) * XPC_NCHANNELS, |
97 | GFP_KERNEL); | 121 | GFP_KERNEL); |
98 | if (part->channels == NULL) { | 122 | if (part->channels == NULL) { |
99 | dev_err(xpc_chan, "can't get memory for channels\n"); | 123 | dev_err(xpc_chan, "can't get memory for channels\n"); |
100 | return xpcNoMemory; | 124 | return xpcNoMemory; |
101 | } | 125 | } |
102 | memset(part->channels, 0, sizeof(struct xpc_channel) * XPC_NCHANNELS); | ||
103 | 126 | ||
104 | part->nchannels = XPC_NCHANNELS; | 127 | part->nchannels = XPC_NCHANNELS; |
105 | 128 | ||
106 | 129 | ||
107 | /* allocate all the required GET/PUT values */ | 130 | /* allocate all the required GET/PUT values */ |
108 | 131 | ||
109 | part->local_GPs = xpc_kmalloc_cacheline_aligned(XPC_GP_SIZE, | 132 | part->local_GPs = xpc_kzalloc_cacheline_aligned(XPC_GP_SIZE, |
110 | GFP_KERNEL, &part->local_GPs_base); | 133 | GFP_KERNEL, &part->local_GPs_base); |
111 | if (part->local_GPs == NULL) { | 134 | if (part->local_GPs == NULL) { |
112 | kfree(part->channels); | 135 | kfree(part->channels); |
@@ -115,55 +138,51 @@ xpc_setup_infrastructure(struct xpc_partition *part) | |||
115 | "values\n"); | 138 | "values\n"); |
116 | return xpcNoMemory; | 139 | return xpcNoMemory; |
117 | } | 140 | } |
118 | memset(part->local_GPs, 0, XPC_GP_SIZE); | ||
119 | 141 | ||
120 | part->remote_GPs = xpc_kmalloc_cacheline_aligned(XPC_GP_SIZE, | 142 | part->remote_GPs = xpc_kzalloc_cacheline_aligned(XPC_GP_SIZE, |
121 | GFP_KERNEL, &part->remote_GPs_base); | 143 | GFP_KERNEL, &part->remote_GPs_base); |
122 | if (part->remote_GPs == NULL) { | 144 | if (part->remote_GPs == NULL) { |
123 | kfree(part->channels); | ||
124 | part->channels = NULL; | ||
125 | kfree(part->local_GPs_base); | ||
126 | part->local_GPs = NULL; | ||
127 | dev_err(xpc_chan, "can't get memory for remote get/put " | 145 | dev_err(xpc_chan, "can't get memory for remote get/put " |
128 | "values\n"); | 146 | "values\n"); |
147 | kfree(part->local_GPs_base); | ||
148 | part->local_GPs = NULL; | ||
149 | kfree(part->channels); | ||
150 | part->channels = NULL; | ||
129 | return xpcNoMemory; | 151 | return xpcNoMemory; |
130 | } | 152 | } |
131 | memset(part->remote_GPs, 0, XPC_GP_SIZE); | ||
132 | 153 | ||
133 | 154 | ||
134 | /* allocate all the required open and close args */ | 155 | /* allocate all the required open and close args */ |
135 | 156 | ||
136 | part->local_openclose_args = xpc_kmalloc_cacheline_aligned( | 157 | part->local_openclose_args = xpc_kzalloc_cacheline_aligned( |
137 | XPC_OPENCLOSE_ARGS_SIZE, GFP_KERNEL, | 158 | XPC_OPENCLOSE_ARGS_SIZE, GFP_KERNEL, |
138 | &part->local_openclose_args_base); | 159 | &part->local_openclose_args_base); |
139 | if (part->local_openclose_args == NULL) { | 160 | if (part->local_openclose_args == NULL) { |
140 | kfree(part->channels); | 161 | dev_err(xpc_chan, "can't get memory for local connect args\n"); |
141 | part->channels = NULL; | ||
142 | kfree(part->local_GPs_base); | ||
143 | part->local_GPs = NULL; | ||
144 | kfree(part->remote_GPs_base); | 162 | kfree(part->remote_GPs_base); |
145 | part->remote_GPs = NULL; | 163 | part->remote_GPs = NULL; |
146 | dev_err(xpc_chan, "can't get memory for local connect args\n"); | 164 | kfree(part->local_GPs_base); |
165 | part->local_GPs = NULL; | ||
166 | kfree(part->channels); | ||
167 | part->channels = NULL; | ||
147 | return xpcNoMemory; | 168 | return xpcNoMemory; |
148 | } | 169 | } |
149 | memset(part->local_openclose_args, 0, XPC_OPENCLOSE_ARGS_SIZE); | ||
150 | 170 | ||
151 | part->remote_openclose_args = xpc_kmalloc_cacheline_aligned( | 171 | part->remote_openclose_args = xpc_kzalloc_cacheline_aligned( |
152 | XPC_OPENCLOSE_ARGS_SIZE, GFP_KERNEL, | 172 | XPC_OPENCLOSE_ARGS_SIZE, GFP_KERNEL, |
153 | &part->remote_openclose_args_base); | 173 | &part->remote_openclose_args_base); |
154 | if (part->remote_openclose_args == NULL) { | 174 | if (part->remote_openclose_args == NULL) { |
155 | kfree(part->channels); | 175 | dev_err(xpc_chan, "can't get memory for remote connect args\n"); |
156 | part->channels = NULL; | ||
157 | kfree(part->local_GPs_base); | ||
158 | part->local_GPs = NULL; | ||
159 | kfree(part->remote_GPs_base); | ||
160 | part->remote_GPs = NULL; | ||
161 | kfree(part->local_openclose_args_base); | 176 | kfree(part->local_openclose_args_base); |
162 | part->local_openclose_args = NULL; | 177 | part->local_openclose_args = NULL; |
163 | dev_err(xpc_chan, "can't get memory for remote connect args\n"); | 178 | kfree(part->remote_GPs_base); |
179 | part->remote_GPs = NULL; | ||
180 | kfree(part->local_GPs_base); | ||
181 | part->local_GPs = NULL; | ||
182 | kfree(part->channels); | ||
183 | part->channels = NULL; | ||
164 | return xpcNoMemory; | 184 | return xpcNoMemory; |
165 | } | 185 | } |
166 | memset(part->remote_openclose_args, 0, XPC_OPENCLOSE_ARGS_SIZE); | ||
167 | 186 | ||
168 | 187 | ||
169 | xpc_initialize_channels(part, partid); | 188 | xpc_initialize_channels(part, partid); |
@@ -186,18 +205,18 @@ xpc_setup_infrastructure(struct xpc_partition *part) | |||
186 | ret = request_irq(SGI_XPC_NOTIFY, xpc_notify_IRQ_handler, SA_SHIRQ, | 205 | ret = request_irq(SGI_XPC_NOTIFY, xpc_notify_IRQ_handler, SA_SHIRQ, |
187 | part->IPI_owner, (void *) (u64) partid); | 206 | part->IPI_owner, (void *) (u64) partid); |
188 | if (ret != 0) { | 207 | if (ret != 0) { |
189 | kfree(part->channels); | ||
190 | part->channels = NULL; | ||
191 | kfree(part->local_GPs_base); | ||
192 | part->local_GPs = NULL; | ||
193 | kfree(part->remote_GPs_base); | ||
194 | part->remote_GPs = NULL; | ||
195 | kfree(part->local_openclose_args_base); | ||
196 | part->local_openclose_args = NULL; | ||
197 | kfree(part->remote_openclose_args_base); | ||
198 | part->remote_openclose_args = NULL; | ||
199 | dev_err(xpc_chan, "can't register NOTIFY IRQ handler, " | 208 | dev_err(xpc_chan, "can't register NOTIFY IRQ handler, " |
200 | "errno=%d\n", -ret); | 209 | "errno=%d\n", -ret); |
210 | kfree(part->remote_openclose_args_base); | ||
211 | part->remote_openclose_args = NULL; | ||
212 | kfree(part->local_openclose_args_base); | ||
213 | part->local_openclose_args = NULL; | ||
214 | kfree(part->remote_GPs_base); | ||
215 | part->remote_GPs = NULL; | ||
216 | kfree(part->local_GPs_base); | ||
217 | part->local_GPs = NULL; | ||
218 | kfree(part->channels); | ||
219 | part->channels = NULL; | ||
201 | return xpcLackOfResources; | 220 | return xpcLackOfResources; |
202 | } | 221 | } |
203 | 222 | ||
@@ -446,22 +465,20 @@ xpc_allocate_local_msgqueue(struct xpc_channel *ch) | |||
446 | for (nentries = ch->local_nentries; nentries > 0; nentries--) { | 465 | for (nentries = ch->local_nentries; nentries > 0; nentries--) { |
447 | 466 | ||
448 | nbytes = nentries * ch->msg_size; | 467 | nbytes = nentries * ch->msg_size; |
449 | ch->local_msgqueue = xpc_kmalloc_cacheline_aligned(nbytes, | 468 | ch->local_msgqueue = xpc_kzalloc_cacheline_aligned(nbytes, |
450 | GFP_KERNEL, | 469 | GFP_KERNEL, |
451 | &ch->local_msgqueue_base); | 470 | &ch->local_msgqueue_base); |
452 | if (ch->local_msgqueue == NULL) { | 471 | if (ch->local_msgqueue == NULL) { |
453 | continue; | 472 | continue; |
454 | } | 473 | } |
455 | memset(ch->local_msgqueue, 0, nbytes); | ||
456 | 474 | ||
457 | nbytes = nentries * sizeof(struct xpc_notify); | 475 | nbytes = nentries * sizeof(struct xpc_notify); |
458 | ch->notify_queue = kmalloc(nbytes, GFP_KERNEL); | 476 | ch->notify_queue = kzalloc(nbytes, GFP_KERNEL); |
459 | if (ch->notify_queue == NULL) { | 477 | if (ch->notify_queue == NULL) { |
460 | kfree(ch->local_msgqueue_base); | 478 | kfree(ch->local_msgqueue_base); |
461 | ch->local_msgqueue = NULL; | 479 | ch->local_msgqueue = NULL; |
462 | continue; | 480 | continue; |
463 | } | 481 | } |
464 | memset(ch->notify_queue, 0, nbytes); | ||
465 | 482 | ||
466 | spin_lock_irqsave(&ch->lock, irq_flags); | 483 | spin_lock_irqsave(&ch->lock, irq_flags); |
467 | if (nentries < ch->local_nentries) { | 484 | if (nentries < ch->local_nentries) { |
@@ -501,13 +518,12 @@ xpc_allocate_remote_msgqueue(struct xpc_channel *ch) | |||
501 | for (nentries = ch->remote_nentries; nentries > 0; nentries--) { | 518 | for (nentries = ch->remote_nentries; nentries > 0; nentries--) { |
502 | 519 | ||
503 | nbytes = nentries * ch->msg_size; | 520 | nbytes = nentries * ch->msg_size; |
504 | ch->remote_msgqueue = xpc_kmalloc_cacheline_aligned(nbytes, | 521 | ch->remote_msgqueue = xpc_kzalloc_cacheline_aligned(nbytes, |
505 | GFP_KERNEL, | 522 | GFP_KERNEL, |
506 | &ch->remote_msgqueue_base); | 523 | &ch->remote_msgqueue_base); |
507 | if (ch->remote_msgqueue == NULL) { | 524 | if (ch->remote_msgqueue == NULL) { |
508 | continue; | 525 | continue; |
509 | } | 526 | } |
510 | memset(ch->remote_msgqueue, 0, nbytes); | ||
511 | 527 | ||
512 | spin_lock_irqsave(&ch->lock, irq_flags); | 528 | spin_lock_irqsave(&ch->lock, irq_flags); |
513 | if (nentries < ch->remote_nentries) { | 529 | if (nentries < ch->remote_nentries) { |
diff --git a/arch/ia64/sn/kernel/xpc_main.c b/arch/ia64/sn/kernel/xpc_main.c index 8cbf16432570..99b123a6421a 100644 --- a/arch/ia64/sn/kernel/xpc_main.c +++ b/arch/ia64/sn/kernel/xpc_main.c | |||
@@ -52,7 +52,6 @@ | |||
52 | #include <linux/syscalls.h> | 52 | #include <linux/syscalls.h> |
53 | #include <linux/cache.h> | 53 | #include <linux/cache.h> |
54 | #include <linux/interrupt.h> | 54 | #include <linux/interrupt.h> |
55 | #include <linux/slab.h> | ||
56 | #include <linux/delay.h> | 55 | #include <linux/delay.h> |
57 | #include <linux/reboot.h> | 56 | #include <linux/reboot.h> |
58 | #include <linux/completion.h> | 57 | #include <linux/completion.h> |
diff --git a/arch/ia64/sn/kernel/xpc_partition.c b/arch/ia64/sn/kernel/xpc_partition.c index 88a730e6cfdb..94211429fd0c 100644 --- a/arch/ia64/sn/kernel/xpc_partition.c +++ b/arch/ia64/sn/kernel/xpc_partition.c | |||
@@ -81,6 +81,31 @@ char ____cacheline_aligned xpc_remote_copy_buffer[XPC_RP_HEADER_SIZE + | |||
81 | 81 | ||
82 | 82 | ||
83 | /* | 83 | /* |
84 | * Guarantee that the kmalloc'd memory is cacheline aligned. | ||
85 | */ | ||
86 | static void * | ||
87 | xpc_kmalloc_cacheline_aligned(size_t size, gfp_t flags, void **base) | ||
88 | { | ||
89 | /* see if kmalloc will give us cachline aligned memory by default */ | ||
90 | *base = kmalloc(size, flags); | ||
91 | if (*base == NULL) { | ||
92 | return NULL; | ||
93 | } | ||
94 | if ((u64) *base == L1_CACHE_ALIGN((u64) *base)) { | ||
95 | return *base; | ||
96 | } | ||
97 | kfree(*base); | ||
98 | |||
99 | /* nope, we'll have to do it ourselves */ | ||
100 | *base = kmalloc(size + L1_CACHE_BYTES, flags); | ||
101 | if (*base == NULL) { | ||
102 | return NULL; | ||
103 | } | ||
104 | return (void *) L1_CACHE_ALIGN((u64) *base); | ||
105 | } | ||
106 | |||
107 | |||
108 | /* | ||
84 | * Given a nasid, get the physical address of the partition's reserved page | 109 | * Given a nasid, get the physical address of the partition's reserved page |
85 | * for that nasid. This function returns 0 on any error. | 110 | * for that nasid. This function returns 0 on any error. |
86 | */ | 111 | */ |
@@ -1038,13 +1063,12 @@ xpc_discovery(void) | |||
1038 | remote_vars = (struct xpc_vars *) remote_rp; | 1063 | remote_vars = (struct xpc_vars *) remote_rp; |
1039 | 1064 | ||
1040 | 1065 | ||
1041 | discovered_nasids = kmalloc(sizeof(u64) * xp_nasid_mask_words, | 1066 | discovered_nasids = kzalloc(sizeof(u64) * xp_nasid_mask_words, |
1042 | GFP_KERNEL); | 1067 | GFP_KERNEL); |
1043 | if (discovered_nasids == NULL) { | 1068 | if (discovered_nasids == NULL) { |
1044 | kfree(remote_rp_base); | 1069 | kfree(remote_rp_base); |
1045 | return; | 1070 | return; |
1046 | } | 1071 | } |
1047 | memset(discovered_nasids, 0, sizeof(u64) * xp_nasid_mask_words); | ||
1048 | 1072 | ||
1049 | rp = (struct xpc_rsvd_page *) xpc_rsvd_page; | 1073 | rp = (struct xpc_rsvd_page *) xpc_rsvd_page; |
1050 | 1074 | ||
diff --git a/arch/ia64/sn/pci/pcibr/pcibr_provider.c b/arch/ia64/sn/pci/pcibr/pcibr_provider.c index 98f716bd92f0..ab1211ef0176 100644 --- a/arch/ia64/sn/pci/pcibr/pcibr_provider.c +++ b/arch/ia64/sn/pci/pcibr/pcibr_provider.c | |||
@@ -74,6 +74,22 @@ static int sal_pcibr_error_interrupt(struct pcibus_info *soft) | |||
74 | return (int)ret_stuff.v0; | 74 | return (int)ret_stuff.v0; |
75 | } | 75 | } |
76 | 76 | ||
77 | u16 sn_ioboard_to_pci_bus(struct pci_bus *pci_bus) | ||
78 | { | ||
79 | s64 rc; | ||
80 | u16 ioboard; | ||
81 | nasid_t nasid = NASID_GET(SN_PCIBUS_BUSSOFT(pci_bus)->bs_base); | ||
82 | |||
83 | rc = ia64_sn_sysctl_ioboard_get(nasid, &ioboard); | ||
84 | if (rc) { | ||
85 | printk(KERN_WARNING "ia64_sn_sysctl_ioboard_get failed: %ld\n", | ||
86 | rc); | ||
87 | return 0; | ||
88 | } | ||
89 | |||
90 | return ioboard; | ||
91 | } | ||
92 | |||
77 | /* | 93 | /* |
78 | * PCI Bridge Error interrupt handler. Gets invoked whenever a PCI | 94 | * PCI Bridge Error interrupt handler. Gets invoked whenever a PCI |
79 | * bridge sends an error interrupt. | 95 | * bridge sends an error interrupt. |
@@ -255,3 +271,4 @@ pcibr_init_provider(void) | |||
255 | 271 | ||
256 | EXPORT_SYMBOL_GPL(sal_pcibr_slot_enable); | 272 | EXPORT_SYMBOL_GPL(sal_pcibr_slot_enable); |
257 | EXPORT_SYMBOL_GPL(sal_pcibr_slot_disable); | 273 | EXPORT_SYMBOL_GPL(sal_pcibr_slot_disable); |
274 | EXPORT_SYMBOL_GPL(sn_ioboard_to_pci_bus); | ||
diff --git a/arch/ia64/sn/pci/tioca_provider.c b/arch/ia64/sn/pci/tioca_provider.c index 7571a4025529..be0176912968 100644 --- a/arch/ia64/sn/pci/tioca_provider.c +++ b/arch/ia64/sn/pci/tioca_provider.c | |||
@@ -377,7 +377,7 @@ tioca_dma_mapped(struct pci_dev *pdev, u64 paddr, size_t req_size) | |||
377 | struct tioca_dmamap *ca_dmamap; | 377 | struct tioca_dmamap *ca_dmamap; |
378 | void *map; | 378 | void *map; |
379 | unsigned long flags; | 379 | unsigned long flags; |
380 | struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(pdev);; | 380 | struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(pdev); |
381 | 381 | ||
382 | tioca_common = (struct tioca_common *)pcidev_info->pdi_pcibus_info; | 382 | tioca_common = (struct tioca_common *)pcidev_info->pdi_pcibus_info; |
383 | tioca_kern = (struct tioca_kernel *)tioca_common->ca_kernel_private; | 383 | tioca_kern = (struct tioca_kernel *)tioca_common->ca_kernel_private; |
diff --git a/arch/ia64/sn/pci/tioce_provider.c b/arch/ia64/sn/pci/tioce_provider.c index e52831ed93eb..fa073cc4b565 100644 --- a/arch/ia64/sn/pci/tioce_provider.c +++ b/arch/ia64/sn/pci/tioce_provider.c | |||
@@ -15,6 +15,124 @@ | |||
15 | #include <asm/sn/pcidev.h> | 15 | #include <asm/sn/pcidev.h> |
16 | #include <asm/sn/pcibus_provider_defs.h> | 16 | #include <asm/sn/pcibus_provider_defs.h> |
17 | #include <asm/sn/tioce_provider.h> | 17 | #include <asm/sn/tioce_provider.h> |
18 | #include <asm/sn/sn2/sn_hwperf.h> | ||
19 | |||
20 | /* | ||
21 | * 1/26/2006 | ||
22 | * | ||
23 | * WAR for SGI PV 944642. For revA TIOCE, need to use the following recipe | ||
24 | * (taken from the above PV) before and after accessing tioce internal MMR's | ||
25 | * to avoid tioce lockups. | ||
26 | * | ||
27 | * The recipe as taken from the PV: | ||
28 | * | ||
29 | * if(mmr address < 0x45000) { | ||
30 | * if(mmr address == 0 or 0x80) | ||
31 | * mmr wrt or read address 0xc0 | ||
32 | * else if(mmr address == 0x148 or 0x200) | ||
33 | * mmr wrt or read address 0x28 | ||
34 | * else | ||
35 | * mmr wrt or read address 0x158 | ||
36 | * | ||
37 | * do desired mmr access (rd or wrt) | ||
38 | * | ||
39 | * if(mmr address == 0x100) | ||
40 | * mmr wrt or read address 0x38 | ||
41 | * mmr wrt or read address 0xb050 | ||
42 | * } else | ||
43 | * do desired mmr access | ||
44 | * | ||
45 | * According to hw, we can use reads instead of writes to the above addres | ||
46 | * | ||
47 | * Note this WAR can only to be used for accessing internal MMR's in the | ||
48 | * TIOCE Coretalk Address Range 0x0 - 0x07ff_ffff. This includes the | ||
49 | * "Local CE Registers and Memories" and "PCI Compatible Config Space" address | ||
50 | * spaces from table 2-1 of the "CE Programmer's Reference Overview" document. | ||
51 | * | ||
52 | * All registers defined in struct tioce will meet that criteria. | ||
53 | */ | ||
54 | |||
55 | static void inline | ||
56 | tioce_mmr_war_pre(struct tioce_kernel *kern, void *mmr_addr) | ||
57 | { | ||
58 | u64 mmr_base; | ||
59 | u64 mmr_offset; | ||
60 | |||
61 | if (kern->ce_common->ce_rev != TIOCE_REV_A) | ||
62 | return; | ||
63 | |||
64 | mmr_base = kern->ce_common->ce_pcibus.bs_base; | ||
65 | mmr_offset = (u64)mmr_addr - mmr_base; | ||
66 | |||
67 | if (mmr_offset < 0x45000) { | ||
68 | u64 mmr_war_offset; | ||
69 | |||
70 | if (mmr_offset == 0 || mmr_offset == 0x80) | ||
71 | mmr_war_offset = 0xc0; | ||
72 | else if (mmr_offset == 0x148 || mmr_offset == 0x200) | ||
73 | mmr_war_offset = 0x28; | ||
74 | else | ||
75 | mmr_war_offset = 0x158; | ||
76 | |||
77 | readq_relaxed((void *)(mmr_base + mmr_war_offset)); | ||
78 | } | ||
79 | } | ||
80 | |||
81 | static void inline | ||
82 | tioce_mmr_war_post(struct tioce_kernel *kern, void *mmr_addr) | ||
83 | { | ||
84 | u64 mmr_base; | ||
85 | u64 mmr_offset; | ||
86 | |||
87 | if (kern->ce_common->ce_rev != TIOCE_REV_A) | ||
88 | return; | ||
89 | |||
90 | mmr_base = kern->ce_common->ce_pcibus.bs_base; | ||
91 | mmr_offset = (u64)mmr_addr - mmr_base; | ||
92 | |||
93 | if (mmr_offset < 0x45000) { | ||
94 | if (mmr_offset == 0x100) | ||
95 | readq_relaxed((void *)(mmr_base + 0x38)); | ||
96 | readq_relaxed((void *)(mmr_base + 0xb050)); | ||
97 | } | ||
98 | } | ||
99 | |||
100 | /* load mmr contents into a variable */ | ||
101 | #define tioce_mmr_load(kern, mmrp, varp) do {\ | ||
102 | tioce_mmr_war_pre(kern, mmrp); \ | ||
103 | *(varp) = readq_relaxed(mmrp); \ | ||
104 | tioce_mmr_war_post(kern, mmrp); \ | ||
105 | } while (0) | ||
106 | |||
107 | /* store variable contents into mmr */ | ||
108 | #define tioce_mmr_store(kern, mmrp, varp) do {\ | ||
109 | tioce_mmr_war_pre(kern, mmrp); \ | ||
110 | writeq(*varp, mmrp); \ | ||
111 | tioce_mmr_war_post(kern, mmrp); \ | ||
112 | } while (0) | ||
113 | |||
114 | /* store immediate value into mmr */ | ||
115 | #define tioce_mmr_storei(kern, mmrp, val) do {\ | ||
116 | tioce_mmr_war_pre(kern, mmrp); \ | ||
117 | writeq(val, mmrp); \ | ||
118 | tioce_mmr_war_post(kern, mmrp); \ | ||
119 | } while (0) | ||
120 | |||
121 | /* set bits (immediate value) into mmr */ | ||
122 | #define tioce_mmr_seti(kern, mmrp, bits) do {\ | ||
123 | u64 tmp; \ | ||
124 | tioce_mmr_load(kern, mmrp, &tmp); \ | ||
125 | tmp |= (bits); \ | ||
126 | tioce_mmr_store(kern, mmrp, &tmp); \ | ||
127 | } while (0) | ||
128 | |||
129 | /* clear bits (immediate value) into mmr */ | ||
130 | #define tioce_mmr_clri(kern, mmrp, bits) do { \ | ||
131 | u64 tmp; \ | ||
132 | tioce_mmr_load(kern, mmrp, &tmp); \ | ||
133 | tmp &= ~(bits); \ | ||
134 | tioce_mmr_store(kern, mmrp, &tmp); \ | ||
135 | } while (0) | ||
18 | 136 | ||
19 | /** | 137 | /** |
20 | * Bus address ranges for the 5 flavors of TIOCE DMA | 138 | * Bus address ranges for the 5 flavors of TIOCE DMA |
@@ -62,9 +180,9 @@ | |||
62 | #define TIOCE_ATE_M40 2 | 180 | #define TIOCE_ATE_M40 2 |
63 | #define TIOCE_ATE_M40S 3 | 181 | #define TIOCE_ATE_M40S 3 |
64 | 182 | ||
65 | #define KB(x) ((x) << 10) | 183 | #define KB(x) ((u64)(x) << 10) |
66 | #define MB(x) ((x) << 20) | 184 | #define MB(x) ((u64)(x) << 20) |
67 | #define GB(x) ((x) << 30) | 185 | #define GB(x) ((u64)(x) << 30) |
68 | 186 | ||
69 | /** | 187 | /** |
70 | * tioce_dma_d64 - create a DMA mapping using 64-bit direct mode | 188 | * tioce_dma_d64 - create a DMA mapping using 64-bit direct mode |
@@ -151,7 +269,7 @@ tioce_alloc_map(struct tioce_kernel *ce_kern, int type, int port, | |||
151 | int last; | 269 | int last; |
152 | int entries; | 270 | int entries; |
153 | int nates; | 271 | int nates; |
154 | int pagesize; | 272 | u64 pagesize; |
155 | u64 *ate_shadow; | 273 | u64 *ate_shadow; |
156 | u64 *ate_reg; | 274 | u64 *ate_reg; |
157 | u64 addr; | 275 | u64 addr; |
@@ -228,7 +346,7 @@ tioce_alloc_map(struct tioce_kernel *ce_kern, int type, int port, | |||
228 | 346 | ||
229 | ate = ATE_MAKE(addr, pagesize); | 347 | ate = ATE_MAKE(addr, pagesize); |
230 | ate_shadow[i + j] = ate; | 348 | ate_shadow[i + j] = ate; |
231 | writeq(ate, &ate_reg[i + j]); | 349 | tioce_mmr_storei(ce_kern, &ate_reg[i + j], ate); |
232 | addr += pagesize; | 350 | addr += pagesize; |
233 | } | 351 | } |
234 | 352 | ||
@@ -272,7 +390,8 @@ tioce_dma_d32(struct pci_dev *pdev, u64 ct_addr) | |||
272 | u64 tmp; | 390 | u64 tmp; |
273 | 391 | ||
274 | ce_kern->ce_port[port].dirmap_shadow = ct_upper; | 392 | ce_kern->ce_port[port].dirmap_shadow = ct_upper; |
275 | writeq(ct_upper, &ce_mmr->ce_ure_dir_map[port]); | 393 | tioce_mmr_storei(ce_kern, &ce_mmr->ce_ure_dir_map[port], |
394 | ct_upper); | ||
276 | tmp = ce_mmr->ce_ure_dir_map[port]; | 395 | tmp = ce_mmr->ce_ure_dir_map[port]; |
277 | dma_ok = 1; | 396 | dma_ok = 1; |
278 | } else | 397 | } else |
@@ -344,7 +463,8 @@ tioce_dma_unmap(struct pci_dev *pdev, dma_addr_t bus_addr, int dir) | |||
344 | if (TIOCE_D32_ADDR(bus_addr)) { | 463 | if (TIOCE_D32_ADDR(bus_addr)) { |
345 | if (--ce_kern->ce_port[port].dirmap_refcnt == 0) { | 464 | if (--ce_kern->ce_port[port].dirmap_refcnt == 0) { |
346 | ce_kern->ce_port[port].dirmap_shadow = 0; | 465 | ce_kern->ce_port[port].dirmap_shadow = 0; |
347 | writeq(0, &ce_mmr->ce_ure_dir_map[port]); | 466 | tioce_mmr_storei(ce_kern, &ce_mmr->ce_ure_dir_map[port], |
467 | 0); | ||
348 | } | 468 | } |
349 | } else { | 469 | } else { |
350 | struct tioce_dmamap *map; | 470 | struct tioce_dmamap *map; |
@@ -365,7 +485,7 @@ tioce_dma_unmap(struct pci_dev *pdev, dma_addr_t bus_addr, int dir) | |||
365 | } else if (--map->refcnt == 0) { | 485 | } else if (--map->refcnt == 0) { |
366 | for (i = 0; i < map->ate_count; i++) { | 486 | for (i = 0; i < map->ate_count; i++) { |
367 | map->ate_shadow[i] = 0; | 487 | map->ate_shadow[i] = 0; |
368 | map->ate_hw[i] = 0; | 488 | tioce_mmr_storei(ce_kern, &map->ate_hw[i], 0); |
369 | } | 489 | } |
370 | 490 | ||
371 | list_del(&map->ce_dmamap_list); | 491 | list_del(&map->ce_dmamap_list); |
@@ -486,7 +606,7 @@ tioce_do_dma_map(struct pci_dev *pdev, u64 paddr, size_t byte_count, | |||
486 | spin_unlock_irqrestore(&ce_kern->ce_lock, flags); | 606 | spin_unlock_irqrestore(&ce_kern->ce_lock, flags); |
487 | 607 | ||
488 | dma_map_done: | 608 | dma_map_done: |
489 | if (mapaddr & barrier) | 609 | if (mapaddr && barrier) |
490 | mapaddr = tioce_dma_barrier(mapaddr, 1); | 610 | mapaddr = tioce_dma_barrier(mapaddr, 1); |
491 | 611 | ||
492 | return mapaddr; | 612 | return mapaddr; |
@@ -541,17 +661,61 @@ tioce_error_intr_handler(int irq, void *arg, struct pt_regs *pt) | |||
541 | soft->ce_pcibus.bs_persist_segment, | 661 | soft->ce_pcibus.bs_persist_segment, |
542 | soft->ce_pcibus.bs_persist_busnum, 0, 0, 0, 0, 0); | 662 | soft->ce_pcibus.bs_persist_busnum, 0, 0, 0, 0, 0); |
543 | 663 | ||
664 | if (ret_stuff.v0) | ||
665 | panic("tioce_error_intr_handler: Fatal TIOCE error"); | ||
666 | |||
544 | return IRQ_HANDLED; | 667 | return IRQ_HANDLED; |
545 | } | 668 | } |
546 | 669 | ||
547 | /** | 670 | /** |
671 | * tioce_reserve_m32 - reserve M32 ate's for the indicated address range | ||
672 | * @tioce_kernel: TIOCE context to reserve ate's for | ||
673 | * @base: starting bus address to reserve | ||
674 | * @limit: last bus address to reserve | ||
675 | * | ||
676 | * If base/limit falls within the range of bus space mapped through the | ||
677 | * M32 space, reserve the resources corresponding to the range. | ||
678 | */ | ||
679 | static void | ||
680 | tioce_reserve_m32(struct tioce_kernel *ce_kern, u64 base, u64 limit) | ||
681 | { | ||
682 | int ate_index, last_ate, ps; | ||
683 | struct tioce *ce_mmr; | ||
684 | |||
685 | if (!TIOCE_M32_ADDR(base)) | ||
686 | return; | ||
687 | |||
688 | ce_mmr = (struct tioce *)ce_kern->ce_common->ce_pcibus.bs_base; | ||
689 | ps = ce_kern->ce_ate3240_pagesize; | ||
690 | ate_index = ATE_PAGE(base, ps); | ||
691 | last_ate = ate_index + ATE_NPAGES(base, limit-base+1, ps) - 1; | ||
692 | |||
693 | if (ate_index < 64) | ||
694 | ate_index = 64; | ||
695 | |||
696 | while (ate_index <= last_ate) { | ||
697 | u64 ate; | ||
698 | |||
699 | ate = ATE_MAKE(0xdeadbeef, ps); | ||
700 | ce_kern->ce_ate3240_shadow[ate_index] = ate; | ||
701 | tioce_mmr_storei(ce_kern, &ce_mmr->ce_ure_ate3240[ate_index], | ||
702 | ate); | ||
703 | ate_index++; | ||
704 | } | ||
705 | } | ||
706 | |||
707 | /** | ||
548 | * tioce_kern_init - init kernel structures related to a given TIOCE | 708 | * tioce_kern_init - init kernel structures related to a given TIOCE |
549 | * @tioce_common: ptr to a cached tioce_common struct that originated in prom | 709 | * @tioce_common: ptr to a cached tioce_common struct that originated in prom |
550 | */ static struct tioce_kernel * | 710 | */ |
711 | static struct tioce_kernel * | ||
551 | tioce_kern_init(struct tioce_common *tioce_common) | 712 | tioce_kern_init(struct tioce_common *tioce_common) |
552 | { | 713 | { |
553 | int i; | 714 | int i; |
715 | int ps; | ||
716 | int dev; | ||
554 | u32 tmp; | 717 | u32 tmp; |
718 | unsigned int seg, bus; | ||
555 | struct tioce *tioce_mmr; | 719 | struct tioce *tioce_mmr; |
556 | struct tioce_kernel *tioce_kern; | 720 | struct tioce_kernel *tioce_kern; |
557 | 721 | ||
@@ -572,9 +736,10 @@ tioce_kern_init(struct tioce_common *tioce_common) | |||
572 | * here to use pci_read_config_xxx() so use the raw_pci_ops vector. | 736 | * here to use pci_read_config_xxx() so use the raw_pci_ops vector. |
573 | */ | 737 | */ |
574 | 738 | ||
575 | raw_pci_ops->read(tioce_common->ce_pcibus.bs_persist_segment, | 739 | seg = tioce_common->ce_pcibus.bs_persist_segment; |
576 | tioce_common->ce_pcibus.bs_persist_busnum, | 740 | bus = tioce_common->ce_pcibus.bs_persist_busnum; |
577 | PCI_DEVFN(2, 0), PCI_SECONDARY_BUS, 1, &tmp); | 741 | |
742 | raw_pci_ops->read(seg, bus, PCI_DEVFN(2, 0), PCI_SECONDARY_BUS, 1,&tmp); | ||
578 | tioce_kern->ce_port1_secondary = (u8) tmp; | 743 | tioce_kern->ce_port1_secondary = (u8) tmp; |
579 | 744 | ||
580 | /* | 745 | /* |
@@ -583,18 +748,76 @@ tioce_kern_init(struct tioce_common *tioce_common) | |||
583 | */ | 748 | */ |
584 | 749 | ||
585 | tioce_mmr = (struct tioce *)tioce_common->ce_pcibus.bs_base; | 750 | tioce_mmr = (struct tioce *)tioce_common->ce_pcibus.bs_base; |
586 | __sn_clrq_relaxed(&tioce_mmr->ce_ure_page_map, CE_URE_PAGESIZE_MASK); | 751 | tioce_mmr_clri(tioce_kern, &tioce_mmr->ce_ure_page_map, |
587 | __sn_setq_relaxed(&tioce_mmr->ce_ure_page_map, CE_URE_256K_PAGESIZE); | 752 | CE_URE_PAGESIZE_MASK); |
588 | tioce_kern->ce_ate3240_pagesize = KB(256); | 753 | tioce_mmr_seti(tioce_kern, &tioce_mmr->ce_ure_page_map, |
754 | CE_URE_256K_PAGESIZE); | ||
755 | ps = tioce_kern->ce_ate3240_pagesize = KB(256); | ||
589 | 756 | ||
590 | for (i = 0; i < TIOCE_NUM_M40_ATES; i++) { | 757 | for (i = 0; i < TIOCE_NUM_M40_ATES; i++) { |
591 | tioce_kern->ce_ate40_shadow[i] = 0; | 758 | tioce_kern->ce_ate40_shadow[i] = 0; |
592 | writeq(0, &tioce_mmr->ce_ure_ate40[i]); | 759 | tioce_mmr_storei(tioce_kern, &tioce_mmr->ce_ure_ate40[i], 0); |
593 | } | 760 | } |
594 | 761 | ||
595 | for (i = 0; i < TIOCE_NUM_M3240_ATES; i++) { | 762 | for (i = 0; i < TIOCE_NUM_M3240_ATES; i++) { |
596 | tioce_kern->ce_ate3240_shadow[i] = 0; | 763 | tioce_kern->ce_ate3240_shadow[i] = 0; |
597 | writeq(0, &tioce_mmr->ce_ure_ate3240[i]); | 764 | tioce_mmr_storei(tioce_kern, &tioce_mmr->ce_ure_ate3240[i], 0); |
765 | } | ||
766 | |||
767 | /* | ||
768 | * Reserve ATE's corresponding to reserved address ranges. These | ||
769 | * include: | ||
770 | * | ||
771 | * Memory space covered by each PPB mem base/limit register | ||
772 | * Memory space covered by each PPB prefetch base/limit register | ||
773 | * | ||
774 | * These bus ranges are for pio (downstream) traffic only, and so | ||
775 | * cannot be used for DMA. | ||
776 | */ | ||
777 | |||
778 | for (dev = 1; dev <= 2; dev++) { | ||
779 | u64 base, limit; | ||
780 | |||
781 | /* mem base/limit */ | ||
782 | |||
783 | raw_pci_ops->read(seg, bus, PCI_DEVFN(dev, 0), | ||
784 | PCI_MEMORY_BASE, 2, &tmp); | ||
785 | base = (u64)tmp << 16; | ||
786 | |||
787 | raw_pci_ops->read(seg, bus, PCI_DEVFN(dev, 0), | ||
788 | PCI_MEMORY_LIMIT, 2, &tmp); | ||
789 | limit = (u64)tmp << 16; | ||
790 | limit |= 0xfffffUL; | ||
791 | |||
792 | if (base < limit) | ||
793 | tioce_reserve_m32(tioce_kern, base, limit); | ||
794 | |||
795 | /* | ||
796 | * prefetch mem base/limit. The tioce ppb's have 64-bit | ||
797 | * decoders, so read the upper portions w/o checking the | ||
798 | * attributes. | ||
799 | */ | ||
800 | |||
801 | raw_pci_ops->read(seg, bus, PCI_DEVFN(dev, 0), | ||
802 | PCI_PREF_MEMORY_BASE, 2, &tmp); | ||
803 | base = ((u64)tmp & PCI_PREF_RANGE_MASK) << 16; | ||
804 | |||
805 | raw_pci_ops->read(seg, bus, PCI_DEVFN(dev, 0), | ||
806 | PCI_PREF_BASE_UPPER32, 4, &tmp); | ||
807 | base |= (u64)tmp << 32; | ||
808 | |||
809 | raw_pci_ops->read(seg, bus, PCI_DEVFN(dev, 0), | ||
810 | PCI_PREF_MEMORY_LIMIT, 2, &tmp); | ||
811 | |||
812 | limit = ((u64)tmp & PCI_PREF_RANGE_MASK) << 16; | ||
813 | limit |= 0xfffffUL; | ||
814 | |||
815 | raw_pci_ops->read(seg, bus, PCI_DEVFN(dev, 0), | ||
816 | PCI_PREF_LIMIT_UPPER32, 4, &tmp); | ||
817 | limit |= (u64)tmp << 32; | ||
818 | |||
819 | if ((base < limit) && TIOCE_M32_ADDR(base)) | ||
820 | tioce_reserve_m32(tioce_kern, base, limit); | ||
598 | } | 821 | } |
599 | 822 | ||
600 | return tioce_kern; | 823 | return tioce_kern; |
@@ -614,6 +837,7 @@ tioce_force_interrupt(struct sn_irq_info *sn_irq_info) | |||
614 | { | 837 | { |
615 | struct pcidev_info *pcidev_info; | 838 | struct pcidev_info *pcidev_info; |
616 | struct tioce_common *ce_common; | 839 | struct tioce_common *ce_common; |
840 | struct tioce_kernel *ce_kern; | ||
617 | struct tioce *ce_mmr; | 841 | struct tioce *ce_mmr; |
618 | u64 force_int_val; | 842 | u64 force_int_val; |
619 | 843 | ||
@@ -629,6 +853,29 @@ tioce_force_interrupt(struct sn_irq_info *sn_irq_info) | |||
629 | 853 | ||
630 | ce_common = (struct tioce_common *)pcidev_info->pdi_pcibus_info; | 854 | ce_common = (struct tioce_common *)pcidev_info->pdi_pcibus_info; |
631 | ce_mmr = (struct tioce *)ce_common->ce_pcibus.bs_base; | 855 | ce_mmr = (struct tioce *)ce_common->ce_pcibus.bs_base; |
856 | ce_kern = (struct tioce_kernel *)ce_common->ce_kernel_private; | ||
857 | |||
858 | /* | ||
859 | * TIOCE Rev A workaround (PV 945826), force an interrupt by writing | ||
860 | * the TIO_INTx register directly (1/26/2006) | ||
861 | */ | ||
862 | if (ce_common->ce_rev == TIOCE_REV_A) { | ||
863 | u64 int_bit_mask = (1ULL << sn_irq_info->irq_int_bit); | ||
864 | u64 status; | ||
865 | |||
866 | tioce_mmr_load(ce_kern, &ce_mmr->ce_adm_int_status, &status); | ||
867 | if (status & int_bit_mask) { | ||
868 | u64 force_irq = (1 << 8) | sn_irq_info->irq_irq; | ||
869 | u64 ctalk = sn_irq_info->irq_xtalkaddr; | ||
870 | u64 nasid, offset; | ||
871 | |||
872 | nasid = (ctalk & CTALK_NASID_MASK) >> CTALK_NASID_SHFT; | ||
873 | offset = (ctalk & CTALK_NODE_OFFSET); | ||
874 | HUB_S(TIO_IOSPACE_ADDR(nasid, offset), force_irq); | ||
875 | } | ||
876 | |||
877 | return; | ||
878 | } | ||
632 | 879 | ||
633 | /* | 880 | /* |
634 | * irq_int_bit is originally set up by prom, and holds the interrupt | 881 | * irq_int_bit is originally set up by prom, and holds the interrupt |
@@ -666,7 +913,7 @@ tioce_force_interrupt(struct sn_irq_info *sn_irq_info) | |||
666 | default: | 913 | default: |
667 | return; | 914 | return; |
668 | } | 915 | } |
669 | writeq(force_int_val, &ce_mmr->ce_adm_force_int); | 916 | tioce_mmr_storei(ce_kern, &ce_mmr->ce_adm_force_int, force_int_val); |
670 | } | 917 | } |
671 | 918 | ||
672 | /** | 919 | /** |
@@ -685,6 +932,7 @@ tioce_target_interrupt(struct sn_irq_info *sn_irq_info) | |||
685 | { | 932 | { |
686 | struct pcidev_info *pcidev_info; | 933 | struct pcidev_info *pcidev_info; |
687 | struct tioce_common *ce_common; | 934 | struct tioce_common *ce_common; |
935 | struct tioce_kernel *ce_kern; | ||
688 | struct tioce *ce_mmr; | 936 | struct tioce *ce_mmr; |
689 | int bit; | 937 | int bit; |
690 | u64 vector; | 938 | u64 vector; |
@@ -695,14 +943,15 @@ tioce_target_interrupt(struct sn_irq_info *sn_irq_info) | |||
695 | 943 | ||
696 | ce_common = (struct tioce_common *)pcidev_info->pdi_pcibus_info; | 944 | ce_common = (struct tioce_common *)pcidev_info->pdi_pcibus_info; |
697 | ce_mmr = (struct tioce *)ce_common->ce_pcibus.bs_base; | 945 | ce_mmr = (struct tioce *)ce_common->ce_pcibus.bs_base; |
946 | ce_kern = (struct tioce_kernel *)ce_common->ce_kernel_private; | ||
698 | 947 | ||
699 | bit = sn_irq_info->irq_int_bit; | 948 | bit = sn_irq_info->irq_int_bit; |
700 | 949 | ||
701 | __sn_setq_relaxed(&ce_mmr->ce_adm_int_mask, (1UL << bit)); | 950 | tioce_mmr_seti(ce_kern, &ce_mmr->ce_adm_int_mask, (1UL << bit)); |
702 | vector = (u64)sn_irq_info->irq_irq << INTR_VECTOR_SHFT; | 951 | vector = (u64)sn_irq_info->irq_irq << INTR_VECTOR_SHFT; |
703 | vector |= sn_irq_info->irq_xtalkaddr; | 952 | vector |= sn_irq_info->irq_xtalkaddr; |
704 | writeq(vector, &ce_mmr->ce_adm_int_dest[bit]); | 953 | tioce_mmr_storei(ce_kern, &ce_mmr->ce_adm_int_dest[bit], vector); |
705 | __sn_clrq_relaxed(&ce_mmr->ce_adm_int_mask, (1UL << bit)); | 954 | tioce_mmr_clri(ce_kern, &ce_mmr->ce_adm_int_mask, (1UL << bit)); |
706 | 955 | ||
707 | tioce_force_interrupt(sn_irq_info); | 956 | tioce_force_interrupt(sn_irq_info); |
708 | } | 957 | } |
@@ -721,7 +970,11 @@ tioce_target_interrupt(struct sn_irq_info *sn_irq_info) | |||
721 | static void * | 970 | static void * |
722 | tioce_bus_fixup(struct pcibus_bussoft *prom_bussoft, struct pci_controller *controller) | 971 | tioce_bus_fixup(struct pcibus_bussoft *prom_bussoft, struct pci_controller *controller) |
723 | { | 972 | { |
973 | int my_nasid; | ||
974 | cnodeid_t my_cnode, mem_cnode; | ||
724 | struct tioce_common *tioce_common; | 975 | struct tioce_common *tioce_common; |
976 | struct tioce_kernel *tioce_kern; | ||
977 | struct tioce *tioce_mmr; | ||
725 | 978 | ||
726 | /* | 979 | /* |
727 | * Allocate kernel bus soft and copy from prom. | 980 | * Allocate kernel bus soft and copy from prom. |
@@ -734,11 +987,23 @@ tioce_bus_fixup(struct pcibus_bussoft *prom_bussoft, struct pci_controller *cont | |||
734 | memcpy(tioce_common, prom_bussoft, sizeof(struct tioce_common)); | 987 | memcpy(tioce_common, prom_bussoft, sizeof(struct tioce_common)); |
735 | tioce_common->ce_pcibus.bs_base |= __IA64_UNCACHED_OFFSET; | 988 | tioce_common->ce_pcibus.bs_base |= __IA64_UNCACHED_OFFSET; |
736 | 989 | ||
737 | if (tioce_kern_init(tioce_common) == NULL) { | 990 | tioce_kern = tioce_kern_init(tioce_common); |
991 | if (tioce_kern == NULL) { | ||
738 | kfree(tioce_common); | 992 | kfree(tioce_common); |
739 | return NULL; | 993 | return NULL; |
740 | } | 994 | } |
741 | 995 | ||
996 | /* | ||
997 | * Clear out any transient errors before registering the error | ||
998 | * interrupt handler. | ||
999 | */ | ||
1000 | |||
1001 | tioce_mmr = (struct tioce *)tioce_common->ce_pcibus.bs_base; | ||
1002 | tioce_mmr_seti(tioce_kern, &tioce_mmr->ce_adm_int_status_alias, ~0ULL); | ||
1003 | tioce_mmr_seti(tioce_kern, &tioce_mmr->ce_adm_error_summary_alias, | ||
1004 | ~0ULL); | ||
1005 | tioce_mmr_seti(tioce_kern, &tioce_mmr->ce_dre_comp_err_addr, ~0ULL); | ||
1006 | |||
742 | if (request_irq(SGI_PCIASIC_ERROR, | 1007 | if (request_irq(SGI_PCIASIC_ERROR, |
743 | tioce_error_intr_handler, | 1008 | tioce_error_intr_handler, |
744 | SA_SHIRQ, "TIOCE error", (void *)tioce_common)) | 1009 | SA_SHIRQ, "TIOCE error", (void *)tioce_common)) |
@@ -750,6 +1015,21 @@ tioce_bus_fixup(struct pcibus_bussoft *prom_bussoft, struct pci_controller *cont | |||
750 | tioce_common->ce_pcibus.bs_persist_segment, | 1015 | tioce_common->ce_pcibus.bs_persist_segment, |
751 | tioce_common->ce_pcibus.bs_persist_busnum); | 1016 | tioce_common->ce_pcibus.bs_persist_busnum); |
752 | 1017 | ||
1018 | /* | ||
1019 | * identify closest nasid for memory allocations | ||
1020 | */ | ||
1021 | |||
1022 | my_nasid = NASID_GET(tioce_common->ce_pcibus.bs_base); | ||
1023 | my_cnode = nasid_to_cnodeid(my_nasid); | ||
1024 | |||
1025 | if (sn_hwperf_get_nearest_node(my_cnode, &mem_cnode, NULL) < 0) { | ||
1026 | printk(KERN_WARNING "tioce_bus_fixup: failed to find " | ||
1027 | "closest node with MEM to TIO node %d\n", my_cnode); | ||
1028 | mem_cnode = (cnodeid_t)-1; /* use any node */ | ||
1029 | } | ||
1030 | |||
1031 | controller->node = mem_cnode; | ||
1032 | |||
753 | return tioce_common; | 1033 | return tioce_common; |
754 | } | 1034 | } |
755 | 1035 | ||