diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-05-05 16:30:23 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-05-05 16:30:23 -0400 |
commit | fabb5c4e4a474ff0f7d6c1d3466a1b79bbce5f49 (patch) | |
tree | c77845e116145fe4e5f172c39f4da2f87b8476ce | |
parent | aa12b2842aba8cc367a2e1ddb5c6ae4fd8ddb1da (diff) | |
parent | d6444514b89098284099c17b9f168ef6236d3e8f (diff) |
Merge master.kernel.org:/pub/scm/linux/kernel/git/jejb/voyager-2.6
* master.kernel.org:/pub/scm/linux/kernel/git/jejb/voyager-2.6:
[VOYAGER] add smp alternatives
[VOYAGER] Use modern techniques to setup and teardown low identiy mappings.
[VOYAGER] Convert the monitor thread to use the kthread API
[VOYAGER] clockevents driver: bring voyager in to line
[VOYAGER] clockevents: correct boot cpu is zero assumption
[VOYAGER] add smp_call_function_single
-rw-r--r-- | arch/i386/kernel/i8253.c | 2 | ||||
-rw-r--r-- | arch/i386/mach-voyager/setup.c | 8 | ||||
-rw-r--r-- | arch/i386/mach-voyager/voyager_cat.c | 4 | ||||
-rw-r--r-- | arch/i386/mach-voyager/voyager_smp.c | 97 | ||||
-rw-r--r-- | arch/i386/mach-voyager/voyager_thread.c | 69 | ||||
-rw-r--r-- | include/asm-i386/voyager.h | 6 |
6 files changed, 84 insertions, 102 deletions
diff --git a/arch/i386/kernel/i8253.c b/arch/i386/kernel/i8253.c index 10cef5ca8a5b..f8a3c4054c70 100644 --- a/arch/i386/kernel/i8253.c +++ b/arch/i386/kernel/i8253.c | |||
@@ -110,7 +110,7 @@ void __init setup_pit_timer(void) | |||
110 | * Start pit with the boot cpu mask and make it global after the | 110 | * Start pit with the boot cpu mask and make it global after the |
111 | * IO_APIC has been initialized. | 111 | * IO_APIC has been initialized. |
112 | */ | 112 | */ |
113 | pit_clockevent.cpumask = cpumask_of_cpu(0); | 113 | pit_clockevent.cpumask = cpumask_of_cpu(smp_processor_id()); |
114 | pit_clockevent.mult = div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC, 32); | 114 | pit_clockevent.mult = div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC, 32); |
115 | pit_clockevent.max_delta_ns = | 115 | pit_clockevent.max_delta_ns = |
116 | clockevent_delta2ns(0x7FFF, &pit_clockevent); | 116 | clockevent_delta2ns(0x7FFF, &pit_clockevent); |
diff --git a/arch/i386/mach-voyager/setup.c b/arch/i386/mach-voyager/setup.c index cfa16c151c8f..447bb105cf58 100644 --- a/arch/i386/mach-voyager/setup.c +++ b/arch/i386/mach-voyager/setup.c | |||
@@ -40,10 +40,16 @@ void __init trap_init_hook(void) | |||
40 | { | 40 | { |
41 | } | 41 | } |
42 | 42 | ||
43 | static struct irqaction irq0 = { timer_interrupt, IRQF_DISABLED, CPU_MASK_NONE, "timer", NULL, NULL}; | 43 | static struct irqaction irq0 = { |
44 | .handler = timer_interrupt, | ||
45 | .flags = IRQF_DISABLED | IRQF_NOBALANCING, | ||
46 | .mask = CPU_MASK_NONE, | ||
47 | .name = "timer" | ||
48 | }; | ||
44 | 49 | ||
45 | void __init time_init_hook(void) | 50 | void __init time_init_hook(void) |
46 | { | 51 | { |
52 | irq0.mask = cpumask_of_cpu(safe_smp_processor_id()); | ||
47 | setup_irq(0, &irq0); | 53 | setup_irq(0, &irq0); |
48 | } | 54 | } |
49 | 55 | ||
diff --git a/arch/i386/mach-voyager/voyager_cat.c b/arch/i386/mach-voyager/voyager_cat.c index 943a9473b138..26a2d4c54b68 100644 --- a/arch/i386/mach-voyager/voyager_cat.c +++ b/arch/i386/mach-voyager/voyager_cat.c | |||
@@ -1111,7 +1111,7 @@ voyager_cat_do_common_interrupt(void) | |||
1111 | printk(KERN_ERR "Voyager front panel switch turned off\n"); | 1111 | printk(KERN_ERR "Voyager front panel switch turned off\n"); |
1112 | voyager_status.switch_off = 1; | 1112 | voyager_status.switch_off = 1; |
1113 | voyager_status.request_from_kernel = 1; | 1113 | voyager_status.request_from_kernel = 1; |
1114 | up(&kvoyagerd_sem); | 1114 | wake_up_process(voyager_thread); |
1115 | } | 1115 | } |
1116 | /* Tell the hardware we're taking care of the | 1116 | /* Tell the hardware we're taking care of the |
1117 | * shutdown, otherwise it will power the box off | 1117 | * shutdown, otherwise it will power the box off |
@@ -1157,7 +1157,7 @@ voyager_cat_do_common_interrupt(void) | |||
1157 | outb(VOYAGER_CAT_END, CAT_CMD); | 1157 | outb(VOYAGER_CAT_END, CAT_CMD); |
1158 | voyager_status.power_fail = 1; | 1158 | voyager_status.power_fail = 1; |
1159 | voyager_status.request_from_kernel = 1; | 1159 | voyager_status.request_from_kernel = 1; |
1160 | up(&kvoyagerd_sem); | 1160 | wake_up_process(voyager_thread); |
1161 | } | 1161 | } |
1162 | 1162 | ||
1163 | 1163 | ||
diff --git a/arch/i386/mach-voyager/voyager_smp.c b/arch/i386/mach-voyager/voyager_smp.c index 74aeedf277f4..fe0ed393294c 100644 --- a/arch/i386/mach-voyager/voyager_smp.c +++ b/arch/i386/mach-voyager/voyager_smp.c | |||
@@ -536,15 +536,6 @@ do_boot_cpu(__u8 cpu) | |||
536 | & ~( voyager_extended_vic_processors | 536 | & ~( voyager_extended_vic_processors |
537 | & voyager_allowed_boot_processors); | 537 | & voyager_allowed_boot_processors); |
538 | 538 | ||
539 | /* For the 486, we can't use the 4Mb page table trick, so | ||
540 | * must map a region of memory */ | ||
541 | #ifdef CONFIG_M486 | ||
542 | int i; | ||
543 | unsigned long *page_table_copies = (unsigned long *) | ||
544 | __get_free_page(GFP_KERNEL); | ||
545 | #endif | ||
546 | pgd_t orig_swapper_pg_dir0; | ||
547 | |||
548 | /* This is an area in head.S which was used to set up the | 539 | /* This is an area in head.S which was used to set up the |
549 | * initial kernel stack. We need to alter this to give the | 540 | * initial kernel stack. We need to alter this to give the |
550 | * booting CPU a new stack (taken from its idle process) */ | 541 | * booting CPU a new stack (taken from its idle process) */ |
@@ -573,6 +564,8 @@ do_boot_cpu(__u8 cpu) | |||
573 | hijack_source.idt.Segment = (start_phys_address >> 4) & 0xFFFF; | 564 | hijack_source.idt.Segment = (start_phys_address >> 4) & 0xFFFF; |
574 | 565 | ||
575 | cpucount++; | 566 | cpucount++; |
567 | alternatives_smp_switch(1); | ||
568 | |||
576 | idle = fork_idle(cpu); | 569 | idle = fork_idle(cpu); |
577 | if(IS_ERR(idle)) | 570 | if(IS_ERR(idle)) |
578 | panic("failed fork for CPU%d", cpu); | 571 | panic("failed fork for CPU%d", cpu); |
@@ -595,24 +588,11 @@ do_boot_cpu(__u8 cpu) | |||
595 | VDEBUG(("VOYAGER SMP: Booting CPU%d at 0x%lx[%x:%x], stack %p\n", cpu, | 588 | VDEBUG(("VOYAGER SMP: Booting CPU%d at 0x%lx[%x:%x], stack %p\n", cpu, |
596 | (unsigned long)hijack_source.val, hijack_source.idt.Segment, | 589 | (unsigned long)hijack_source.val, hijack_source.idt.Segment, |
597 | hijack_source.idt.Offset, stack_start.esp)); | 590 | hijack_source.idt.Offset, stack_start.esp)); |
598 | /* set the original swapper_pg_dir[0] to map 0 to 4Mb transparently | 591 | |
599 | * (so that the booting CPU can find start_32 */ | 592 | /* init lowmem identity mapping */ |
600 | orig_swapper_pg_dir0 = swapper_pg_dir[0]; | 593 | clone_pgd_range(swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS, |
601 | #ifdef CONFIG_M486 | 594 | min_t(unsigned long, KERNEL_PGD_PTRS, USER_PGD_PTRS)); |
602 | if(page_table_copies == NULL) | 595 | flush_tlb_all(); |
603 | panic("No free memory for 486 page tables\n"); | ||
604 | for(i = 0; i < PAGE_SIZE/sizeof(unsigned long); i++) | ||
605 | page_table_copies[i] = (i * PAGE_SIZE) | ||
606 | | _PAGE_RW | _PAGE_USER | _PAGE_PRESENT; | ||
607 | |||
608 | ((unsigned long *)swapper_pg_dir)[0] = | ||
609 | ((virt_to_phys(page_table_copies)) & PAGE_MASK) | ||
610 | | _PAGE_RW | _PAGE_USER | _PAGE_PRESENT; | ||
611 | #else | ||
612 | ((unsigned long *)swapper_pg_dir)[0] = | ||
613 | (virt_to_phys(pg0) & PAGE_MASK) | ||
614 | | _PAGE_RW | _PAGE_USER | _PAGE_PRESENT; | ||
615 | #endif | ||
616 | 596 | ||
617 | if(quad_boot) { | 597 | if(quad_boot) { |
618 | printk("CPU %d: non extended Quad boot\n", cpu); | 598 | printk("CPU %d: non extended Quad boot\n", cpu); |
@@ -655,11 +635,7 @@ do_boot_cpu(__u8 cpu) | |||
655 | udelay(100); | 635 | udelay(100); |
656 | } | 636 | } |
657 | /* reset the page table */ | 637 | /* reset the page table */ |
658 | swapper_pg_dir[0] = orig_swapper_pg_dir0; | 638 | zap_low_mappings(); |
659 | local_flush_tlb(); | ||
660 | #ifdef CONFIG_M486 | ||
661 | free_page((unsigned long)page_table_copies); | ||
662 | #endif | ||
663 | 639 | ||
664 | if (cpu_booted_map) { | 640 | if (cpu_booted_map) { |
665 | VDEBUG(("CPU%d: Booted successfully, back in CPU %d\n", | 641 | VDEBUG(("CPU%d: Booted successfully, back in CPU %d\n", |
@@ -1082,20 +1058,11 @@ smp_call_function_interrupt(void) | |||
1082 | } | 1058 | } |
1083 | } | 1059 | } |
1084 | 1060 | ||
1085 | /* Call this function on all CPUs using the function_interrupt above | 1061 | static int |
1086 | <func> The function to run. This must be fast and non-blocking. | 1062 | __smp_call_function_mask (void (*func) (void *info), void *info, int retry, |
1087 | <info> An arbitrary pointer to pass to the function. | 1063 | int wait, __u32 mask) |
1088 | <retry> If true, keep retrying until ready. | ||
1089 | <wait> If true, wait until function has completed on other CPUs. | ||
1090 | [RETURNS] 0 on success, else a negative status code. Does not return until | ||
1091 | remote CPUs are nearly ready to execute <<func>> or are or have executed. | ||
1092 | */ | ||
1093 | int | ||
1094 | smp_call_function (void (*func) (void *info), void *info, int retry, | ||
1095 | int wait) | ||
1096 | { | 1064 | { |
1097 | struct call_data_struct data; | 1065 | struct call_data_struct data; |
1098 | __u32 mask = cpus_addr(cpu_online_map)[0]; | ||
1099 | 1066 | ||
1100 | mask &= ~(1<<smp_processor_id()); | 1067 | mask &= ~(1<<smp_processor_id()); |
1101 | 1068 | ||
@@ -1116,7 +1083,7 @@ smp_call_function (void (*func) (void *info), void *info, int retry, | |||
1116 | call_data = &data; | 1083 | call_data = &data; |
1117 | wmb(); | 1084 | wmb(); |
1118 | /* Send a message to all other CPUs and wait for them to respond */ | 1085 | /* Send a message to all other CPUs and wait for them to respond */ |
1119 | send_CPI_allbutself(VIC_CALL_FUNCTION_CPI); | 1086 | send_CPI(mask, VIC_CALL_FUNCTION_CPI); |
1120 | 1087 | ||
1121 | /* Wait for response */ | 1088 | /* Wait for response */ |
1122 | while (data.started) | 1089 | while (data.started) |
@@ -1130,8 +1097,48 @@ smp_call_function (void (*func) (void *info), void *info, int retry, | |||
1130 | 1097 | ||
1131 | return 0; | 1098 | return 0; |
1132 | } | 1099 | } |
1100 | |||
1101 | /* Call this function on all CPUs using the function_interrupt above | ||
1102 | <func> The function to run. This must be fast and non-blocking. | ||
1103 | <info> An arbitrary pointer to pass to the function. | ||
1104 | <retry> If true, keep retrying until ready. | ||
1105 | <wait> If true, wait until function has completed on other CPUs. | ||
1106 | [RETURNS] 0 on success, else a negative status code. Does not return until | ||
1107 | remote CPUs are nearly ready to execute <<func>> or are or have executed. | ||
1108 | */ | ||
1109 | int | ||
1110 | smp_call_function(void (*func) (void *info), void *info, int retry, | ||
1111 | int wait) | ||
1112 | { | ||
1113 | __u32 mask = cpus_addr(cpu_online_map)[0]; | ||
1114 | |||
1115 | return __smp_call_function_mask(func, info, retry, wait, mask); | ||
1116 | } | ||
1133 | EXPORT_SYMBOL(smp_call_function); | 1117 | EXPORT_SYMBOL(smp_call_function); |
1134 | 1118 | ||
1119 | /* | ||
1120 | * smp_call_function_single - Run a function on another CPU | ||
1121 | * @func: The function to run. This must be fast and non-blocking. | ||
1122 | * @info: An arbitrary pointer to pass to the function. | ||
1123 | * @nonatomic: Currently unused. | ||
1124 | * @wait: If true, wait until function has completed on other CPUs. | ||
1125 | * | ||
1126 | * Retrurns 0 on success, else a negative status code. | ||
1127 | * | ||
1128 | * Does not return until the remote CPU is nearly ready to execute <func> | ||
1129 | * or is or has executed. | ||
1130 | */ | ||
1131 | |||
1132 | int | ||
1133 | smp_call_function_single(int cpu, void (*func) (void *info), void *info, | ||
1134 | int nonatomic, int wait) | ||
1135 | { | ||
1136 | __u32 mask = 1 << cpu; | ||
1137 | |||
1138 | return __smp_call_function_mask(func, info, nonatomic, wait, mask); | ||
1139 | } | ||
1140 | EXPORT_SYMBOL(smp_call_function_single); | ||
1141 | |||
1135 | /* Sorry about the name. In an APIC based system, the APICs | 1142 | /* Sorry about the name. In an APIC based system, the APICs |
1136 | * themselves are programmed to send a timer interrupt. This is used | 1143 | * themselves are programmed to send a timer interrupt. This is used |
1137 | * by linux to reschedule the processor. Voyager doesn't have this, | 1144 | * by linux to reschedule the processor. Voyager doesn't have this, |
diff --git a/arch/i386/mach-voyager/voyager_thread.c b/arch/i386/mach-voyager/voyager_thread.c index f39887359e8e..fdc1d926fb2a 100644 --- a/arch/i386/mach-voyager/voyager_thread.c +++ b/arch/i386/mach-voyager/voyager_thread.c | |||
@@ -24,33 +24,16 @@ | |||
24 | #include <linux/kmod.h> | 24 | #include <linux/kmod.h> |
25 | #include <linux/completion.h> | 25 | #include <linux/completion.h> |
26 | #include <linux/sched.h> | 26 | #include <linux/sched.h> |
27 | #include <linux/kthread.h> | ||
27 | #include <asm/desc.h> | 28 | #include <asm/desc.h> |
28 | #include <asm/voyager.h> | 29 | #include <asm/voyager.h> |
29 | #include <asm/vic.h> | 30 | #include <asm/vic.h> |
30 | #include <asm/mtrr.h> | 31 | #include <asm/mtrr.h> |
31 | #include <asm/msr.h> | 32 | #include <asm/msr.h> |
32 | 33 | ||
33 | #define THREAD_NAME "kvoyagerd" | ||
34 | 34 | ||
35 | /* external variables */ | 35 | struct task_struct *voyager_thread; |
36 | int kvoyagerd_running = 0; | 36 | static __u8 set_timeout; |
37 | DECLARE_MUTEX_LOCKED(kvoyagerd_sem); | ||
38 | |||
39 | static int thread(void *); | ||
40 | |||
41 | static __u8 set_timeout = 0; | ||
42 | |||
43 | /* Start the machine monitor thread. Return 1 if OK, 0 if fail */ | ||
44 | static int __init | ||
45 | voyager_thread_start(void) | ||
46 | { | ||
47 | if(kernel_thread(thread, NULL, CLONE_KERNEL) < 0) { | ||
48 | /* This is serious, but not fatal */ | ||
49 | printk(KERN_ERR "Voyager: Failed to create system monitor thread!!!\n"); | ||
50 | return 1; | ||
51 | } | ||
52 | return 0; | ||
53 | } | ||
54 | 37 | ||
55 | static int | 38 | static int |
56 | execute(const char *string) | 39 | execute(const char *string) |
@@ -110,31 +93,15 @@ check_continuing_condition(void) | |||
110 | } | 93 | } |
111 | } | 94 | } |
112 | 95 | ||
113 | static void | ||
114 | wakeup(unsigned long unused) | ||
115 | { | ||
116 | up(&kvoyagerd_sem); | ||
117 | } | ||
118 | |||
119 | static int | 96 | static int |
120 | thread(void *unused) | 97 | thread(void *unused) |
121 | { | 98 | { |
122 | struct timer_list wakeup_timer; | ||
123 | |||
124 | kvoyagerd_running = 1; | ||
125 | |||
126 | daemonize(THREAD_NAME); | ||
127 | |||
128 | set_timeout = 0; | ||
129 | |||
130 | init_timer(&wakeup_timer); | ||
131 | |||
132 | sigfillset(¤t->blocked); | ||
133 | |||
134 | printk(KERN_NOTICE "Voyager starting monitor thread\n"); | 99 | printk(KERN_NOTICE "Voyager starting monitor thread\n"); |
135 | 100 | ||
136 | for(;;) { | 101 | for (;;) { |
137 | down_interruptible(&kvoyagerd_sem); | 102 | set_current_state(TASK_INTERRUPTIBLE); |
103 | schedule_timeout(set_timeout ? HZ : MAX_SCHEDULE_TIMEOUT); | ||
104 | |||
138 | VDEBUG(("Voyager Daemon awoken\n")); | 105 | VDEBUG(("Voyager Daemon awoken\n")); |
139 | if(voyager_status.request_from_kernel == 0) { | 106 | if(voyager_status.request_from_kernel == 0) { |
140 | /* probably awoken from timeout */ | 107 | /* probably awoken from timeout */ |
@@ -143,20 +110,26 @@ thread(void *unused) | |||
143 | check_from_kernel(); | 110 | check_from_kernel(); |
144 | voyager_status.request_from_kernel = 0; | 111 | voyager_status.request_from_kernel = 0; |
145 | } | 112 | } |
146 | if(set_timeout) { | ||
147 | del_timer(&wakeup_timer); | ||
148 | wakeup_timer.expires = HZ + jiffies; | ||
149 | wakeup_timer.function = wakeup; | ||
150 | add_timer(&wakeup_timer); | ||
151 | } | ||
152 | } | 113 | } |
153 | } | 114 | } |
154 | 115 | ||
116 | static int __init | ||
117 | voyager_thread_start(void) | ||
118 | { | ||
119 | voyager_thread = kthread_run(thread, NULL, "kvoyagerd"); | ||
120 | if (IS_ERR(voyager_thread)) { | ||
121 | printk(KERN_ERR "Voyager: Failed to create system monitor thread.\n"); | ||
122 | return PTR_ERR(voyager_thread); | ||
123 | } | ||
124 | return 0; | ||
125 | } | ||
126 | |||
127 | |||
155 | static void __exit | 128 | static void __exit |
156 | voyager_thread_stop(void) | 129 | voyager_thread_stop(void) |
157 | { | 130 | { |
158 | /* FIXME: do nothing at the moment */ | 131 | kthread_stop(voyager_thread); |
159 | } | 132 | } |
160 | 133 | ||
161 | module_init(voyager_thread_start); | 134 | module_init(voyager_thread_start); |
162 | //module_exit(voyager_thread_stop); | 135 | module_exit(voyager_thread_stop); |
diff --git a/include/asm-i386/voyager.h b/include/asm-i386/voyager.h index 5b27838905b2..91a9932937ab 100644 --- a/include/asm-i386/voyager.h +++ b/include/asm-i386/voyager.h | |||
@@ -487,15 +487,11 @@ extern struct voyager_qic_cpi *voyager_quad_cpi_addr[NR_CPUS]; | |||
487 | extern struct voyager_SUS *voyager_SUS; | 487 | extern struct voyager_SUS *voyager_SUS; |
488 | 488 | ||
489 | /* variables exported always */ | 489 | /* variables exported always */ |
490 | extern struct task_struct *voyager_thread; | ||
490 | extern int voyager_level; | 491 | extern int voyager_level; |
491 | extern int kvoyagerd_running; | ||
492 | extern struct semaphore kvoyagerd_sem; | ||
493 | extern struct voyager_status voyager_status; | 492 | extern struct voyager_status voyager_status; |
494 | 493 | ||
495 | |||
496 | |||
497 | /* functions exported by the voyager and voyager_smp modules */ | 494 | /* functions exported by the voyager and voyager_smp modules */ |
498 | |||
499 | extern int voyager_cat_readb(__u8 module, __u8 asic, int reg); | 495 | extern int voyager_cat_readb(__u8 module, __u8 asic, int reg); |
500 | extern void voyager_cat_init(void); | 496 | extern void voyager_cat_init(void); |
501 | extern void voyager_detect(struct voyager_bios_info *); | 497 | extern void voyager_detect(struct voyager_bios_info *); |