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 *); |
