Browse Source

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
Linus Torvalds 18 years ago
parent
commit
fabb5c4e4a

+ 1 - 1
arch/i386/kernel/i8253.c

@@ -110,7 +110,7 @@ void __init setup_pit_timer(void)
 	 * Start pit with the boot cpu mask and make it global after the
 	 * Start pit with the boot cpu mask and make it global after the
 	 * IO_APIC has been initialized.
 	 * IO_APIC has been initialized.
 	 */
 	 */
-	pit_clockevent.cpumask = cpumask_of_cpu(0);
+	pit_clockevent.cpumask = cpumask_of_cpu(smp_processor_id());
 	pit_clockevent.mult = div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC, 32);
 	pit_clockevent.mult = div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC, 32);
 	pit_clockevent.max_delta_ns =
 	pit_clockevent.max_delta_ns =
 		clockevent_delta2ns(0x7FFF, &pit_clockevent);
 		clockevent_delta2ns(0x7FFF, &pit_clockevent);

+ 7 - 1
arch/i386/mach-voyager/setup.c

@@ -40,10 +40,16 @@ void __init trap_init_hook(void)
 {
 {
 }
 }
 
 
-static struct irqaction irq0  = { timer_interrupt, IRQF_DISABLED, CPU_MASK_NONE, "timer", NULL, NULL};
+static struct irqaction irq0  = {
+	.handler = timer_interrupt,
+	.flags = IRQF_DISABLED | IRQF_NOBALANCING,
+	.mask = CPU_MASK_NONE,
+	.name = "timer"
+};
 
 
 void __init time_init_hook(void)
 void __init time_init_hook(void)
 {
 {
+	irq0.mask = cpumask_of_cpu(safe_smp_processor_id());
 	setup_irq(0, &irq0);
 	setup_irq(0, &irq0);
 }
 }
 
 

+ 2 - 2
arch/i386/mach-voyager/voyager_cat.c

@@ -1111,7 +1111,7 @@ voyager_cat_do_common_interrupt(void)
 				printk(KERN_ERR "Voyager front panel switch turned off\n");
 				printk(KERN_ERR "Voyager front panel switch turned off\n");
 				voyager_status.switch_off = 1;
 				voyager_status.switch_off = 1;
 				voyager_status.request_from_kernel = 1;
 				voyager_status.request_from_kernel = 1;
-				up(&kvoyagerd_sem);
+				wake_up_process(voyager_thread);
 			}
 			}
 			/* Tell the hardware we're taking care of the
 			/* Tell the hardware we're taking care of the
 			 * shutdown, otherwise it will power the box off
 			 * shutdown, otherwise it will power the box off
@@ -1157,7 +1157,7 @@ voyager_cat_do_common_interrupt(void)
 			outb(VOYAGER_CAT_END, CAT_CMD);
 			outb(VOYAGER_CAT_END, CAT_CMD);
 			voyager_status.power_fail = 1;
 			voyager_status.power_fail = 1;
 			voyager_status.request_from_kernel = 1;
 			voyager_status.request_from_kernel = 1;
-			up(&kvoyagerd_sem);
+			wake_up_process(voyager_thread);
 		}
 		}
 		
 		
 		
 		

+ 52 - 45
arch/i386/mach-voyager/voyager_smp.c

@@ -536,15 +536,6 @@ do_boot_cpu(__u8 cpu)
 		& ~( voyager_extended_vic_processors
 		& ~( voyager_extended_vic_processors
 		     & voyager_allowed_boot_processors);
 		     & voyager_allowed_boot_processors);
 
 
-	/* For the 486, we can't use the 4Mb page table trick, so
-	 * must map a region of memory */
-#ifdef CONFIG_M486
-	int i;
-	unsigned long *page_table_copies = (unsigned long *)
-		__get_free_page(GFP_KERNEL);
-#endif
-	pgd_t orig_swapper_pg_dir0;
-
 	/* This is an area in head.S which was used to set up the
 	/* This is an area in head.S which was used to set up the
 	 * initial kernel stack.  We need to alter this to give the
 	 * initial kernel stack.  We need to alter this to give the
 	 * booting CPU a new stack (taken from its idle process) */
 	 * booting CPU a new stack (taken from its idle process) */
@@ -573,6 +564,8 @@ do_boot_cpu(__u8 cpu)
 	hijack_source.idt.Segment = (start_phys_address >> 4) & 0xFFFF;
 	hijack_source.idt.Segment = (start_phys_address >> 4) & 0xFFFF;
 
 
 	cpucount++;
 	cpucount++;
+	alternatives_smp_switch(1);
+
 	idle = fork_idle(cpu);
 	idle = fork_idle(cpu);
 	if(IS_ERR(idle))
 	if(IS_ERR(idle))
 		panic("failed fork for CPU%d", cpu);
 		panic("failed fork for CPU%d", cpu);
@@ -595,24 +588,11 @@ do_boot_cpu(__u8 cpu)
 	VDEBUG(("VOYAGER SMP: Booting CPU%d at 0x%lx[%x:%x], stack %p\n", cpu, 
 	VDEBUG(("VOYAGER SMP: Booting CPU%d at 0x%lx[%x:%x], stack %p\n", cpu, 
 		(unsigned long)hijack_source.val, hijack_source.idt.Segment,
 		(unsigned long)hijack_source.val, hijack_source.idt.Segment,
 		hijack_source.idt.Offset, stack_start.esp));
 		hijack_source.idt.Offset, stack_start.esp));
-	/* set the original swapper_pg_dir[0] to map 0 to 4Mb transparently
-	 * (so that the booting CPU can find start_32 */
-	orig_swapper_pg_dir0 = swapper_pg_dir[0];
-#ifdef CONFIG_M486
-	if(page_table_copies == NULL)
-		panic("No free memory for 486 page tables\n");
-	for(i = 0; i < PAGE_SIZE/sizeof(unsigned long); i++)
-		page_table_copies[i] = (i * PAGE_SIZE) 
-			| _PAGE_RW | _PAGE_USER | _PAGE_PRESENT;
-
-	((unsigned long *)swapper_pg_dir)[0] = 
-		((virt_to_phys(page_table_copies)) & PAGE_MASK)
-		| _PAGE_RW | _PAGE_USER | _PAGE_PRESENT;
-#else
-	((unsigned long *)swapper_pg_dir)[0] = 
-		(virt_to_phys(pg0) & PAGE_MASK)
-		| _PAGE_RW | _PAGE_USER | _PAGE_PRESENT;
-#endif
+
+	/* init lowmem identity mapping */
+	clone_pgd_range(swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS,
+			min_t(unsigned long, KERNEL_PGD_PTRS, USER_PGD_PTRS));
+	flush_tlb_all();
 
 
 	if(quad_boot) {
 	if(quad_boot) {
 		printk("CPU %d: non extended Quad boot\n", cpu);
 		printk("CPU %d: non extended Quad boot\n", cpu);
@@ -655,11 +635,7 @@ do_boot_cpu(__u8 cpu)
 		udelay(100);
 		udelay(100);
 	}
 	}
 	/* reset the page table */
 	/* reset the page table */
-	swapper_pg_dir[0] = orig_swapper_pg_dir0;
-	local_flush_tlb();
-#ifdef CONFIG_M486
-	free_page((unsigned long)page_table_copies);
-#endif
+	zap_low_mappings();
 	  
 	  
 	if (cpu_booted_map) {
 	if (cpu_booted_map) {
 		VDEBUG(("CPU%d: Booted successfully, back in CPU %d\n",
 		VDEBUG(("CPU%d: Booted successfully, back in CPU %d\n",
@@ -1082,20 +1058,11 @@ smp_call_function_interrupt(void)
 	}
 	}
 }
 }
 
 
-/* Call this function on all CPUs using the function_interrupt above 
-    <func> The function to run. This must be fast and non-blocking.
-    <info> An arbitrary pointer to pass to the function.
-    <retry> If true, keep retrying until ready.
-    <wait> If true, wait until function has completed on other CPUs.
-    [RETURNS] 0 on success, else a negative status code. Does not return until
-    remote CPUs are nearly ready to execute <<func>> or are or have executed.
-*/
-int
-smp_call_function (void (*func) (void *info), void *info, int retry,
-		   int wait)
+static int
+__smp_call_function_mask (void (*func) (void *info), void *info, int retry,
+			  int wait, __u32 mask)
 {
 {
 	struct call_data_struct data;
 	struct call_data_struct data;
-	__u32 mask = cpus_addr(cpu_online_map)[0];
 
 
 	mask &= ~(1<<smp_processor_id());
 	mask &= ~(1<<smp_processor_id());
 
 
@@ -1116,7 +1083,7 @@ smp_call_function (void (*func) (void *info), void *info, int retry,
 	call_data = &data;
 	call_data = &data;
 	wmb();
 	wmb();
 	/* Send a message to all other CPUs and wait for them to respond */
 	/* Send a message to all other CPUs and wait for them to respond */
-	send_CPI_allbutself(VIC_CALL_FUNCTION_CPI);
+	send_CPI(mask, VIC_CALL_FUNCTION_CPI);
 
 
 	/* Wait for response */
 	/* Wait for response */
 	while (data.started)
 	while (data.started)
@@ -1130,8 +1097,48 @@ smp_call_function (void (*func) (void *info), void *info, int retry,
 
 
 	return 0;
 	return 0;
 }
 }
+
+/* Call this function on all CPUs using the function_interrupt above
+    <func> The function to run. This must be fast and non-blocking.
+    <info> An arbitrary pointer to pass to the function.
+    <retry> If true, keep retrying until ready.
+    <wait> If true, wait until function has completed on other CPUs.
+    [RETURNS] 0 on success, else a negative status code. Does not return until
+    remote CPUs are nearly ready to execute <<func>> or are or have executed.
+*/
+int
+smp_call_function(void (*func) (void *info), void *info, int retry,
+		   int wait)
+{
+	__u32 mask = cpus_addr(cpu_online_map)[0];
+
+	return __smp_call_function_mask(func, info, retry, wait, mask);
+}
 EXPORT_SYMBOL(smp_call_function);
 EXPORT_SYMBOL(smp_call_function);
 
 
+/*
+ * smp_call_function_single - Run a function on another CPU
+ * @func: The function to run. This must be fast and non-blocking.
+ * @info: An arbitrary pointer to pass to the function.
+ * @nonatomic: Currently unused.
+ * @wait: If true, wait until function has completed on other CPUs.
+ *
+ * Retrurns 0 on success, else a negative status code.
+ *
+ * Does not return until the remote CPU is nearly ready to execute <func>
+ * or is or has executed.
+ */
+
+int
+smp_call_function_single(int cpu, void (*func) (void *info), void *info,
+			 int nonatomic, int wait)
+{
+	__u32 mask = 1 << cpu;
+
+	return __smp_call_function_mask(func, info, nonatomic, wait, mask);
+}
+EXPORT_SYMBOL(smp_call_function_single);
+
 /* Sorry about the name.  In an APIC based system, the APICs
 /* Sorry about the name.  In an APIC based system, the APICs
  * themselves are programmed to send a timer interrupt.  This is used
  * themselves are programmed to send a timer interrupt.  This is used
  * by linux to reschedule the processor.  Voyager doesn't have this,
  * by linux to reschedule the processor.  Voyager doesn't have this,

+ 21 - 48
arch/i386/mach-voyager/voyager_thread.c

@@ -24,33 +24,16 @@
 #include <linux/kmod.h>
 #include <linux/kmod.h>
 #include <linux/completion.h>
 #include <linux/completion.h>
 #include <linux/sched.h>
 #include <linux/sched.h>
+#include <linux/kthread.h>
 #include <asm/desc.h>
 #include <asm/desc.h>
 #include <asm/voyager.h>
 #include <asm/voyager.h>
 #include <asm/vic.h>
 #include <asm/vic.h>
 #include <asm/mtrr.h>
 #include <asm/mtrr.h>
 #include <asm/msr.h>
 #include <asm/msr.h>
 
 
-#define THREAD_NAME "kvoyagerd"
 
 
-/* external variables */
-int kvoyagerd_running = 0;
-DECLARE_MUTEX_LOCKED(kvoyagerd_sem);
-
-static int thread(void *);
-
-static __u8 set_timeout = 0;
-
-/* Start the machine monitor thread.  Return 1 if OK, 0 if fail */
-static int __init
-voyager_thread_start(void)
-{
-	if(kernel_thread(thread, NULL, CLONE_KERNEL) < 0) {
-		/* This is serious, but not fatal */
-		printk(KERN_ERR "Voyager: Failed to create system monitor thread!!!\n");
-		return 1;
-	}
-	return 0;
-}
+struct task_struct *voyager_thread;
+static __u8 set_timeout;
 
 
 static int
 static int
 execute(const char *string)
 execute(const char *string)
@@ -110,31 +93,15 @@ check_continuing_condition(void)
 	}
 	}
 }
 }
 
 
-static void
-wakeup(unsigned long unused)
-{
-	up(&kvoyagerd_sem);
-}
-
 static int
 static int
 thread(void *unused)
 thread(void *unused)
 {
 {
-	struct timer_list wakeup_timer;
-
-	kvoyagerd_running = 1;
-
-	daemonize(THREAD_NAME);
-
-	set_timeout = 0;
-
-	init_timer(&wakeup_timer);
-
-	sigfillset(&current->blocked);
-
 	printk(KERN_NOTICE "Voyager starting monitor thread\n");
 	printk(KERN_NOTICE "Voyager starting monitor thread\n");
 
 
-	for(;;) {
-		down_interruptible(&kvoyagerd_sem);
+	for (;;) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(set_timeout ? HZ : MAX_SCHEDULE_TIMEOUT);
+
 		VDEBUG(("Voyager Daemon awoken\n"));
 		VDEBUG(("Voyager Daemon awoken\n"));
 		if(voyager_status.request_from_kernel == 0) {
 		if(voyager_status.request_from_kernel == 0) {
 			/* probably awoken from timeout */
 			/* probably awoken from timeout */
@@ -143,20 +110,26 @@ thread(void *unused)
 			check_from_kernel();
 			check_from_kernel();
 			voyager_status.request_from_kernel = 0;
 			voyager_status.request_from_kernel = 0;
 		}
 		}
-		if(set_timeout) {
-			del_timer(&wakeup_timer);
-			wakeup_timer.expires = HZ + jiffies;
-			wakeup_timer.function = wakeup;
-			add_timer(&wakeup_timer);
-		}
 	}
 	}
 }
 }
 
 
+static int __init
+voyager_thread_start(void)
+{
+	voyager_thread = kthread_run(thread, NULL, "kvoyagerd");
+	if (IS_ERR(voyager_thread)) {
+		printk(KERN_ERR "Voyager: Failed to create system monitor thread.\n");
+		return PTR_ERR(voyager_thread);
+	}
+	return 0;
+}
+
+
 static void __exit
 static void __exit
 voyager_thread_stop(void)
 voyager_thread_stop(void)
 {
 {
-	/* FIXME: do nothing at the moment */
+	kthread_stop(voyager_thread);
 }
 }
 
 
 module_init(voyager_thread_start);
 module_init(voyager_thread_start);
-//module_exit(voyager_thread_stop);
+module_exit(voyager_thread_stop);

+ 1 - 5
include/asm-i386/voyager.h

@@ -487,15 +487,11 @@ extern struct voyager_qic_cpi *voyager_quad_cpi_addr[NR_CPUS];
 extern struct voyager_SUS *voyager_SUS;
 extern struct voyager_SUS *voyager_SUS;
 
 
 /* variables exported always */
 /* variables exported always */
+extern struct task_struct *voyager_thread;
 extern int voyager_level;
 extern int voyager_level;
-extern int kvoyagerd_running;
-extern struct semaphore kvoyagerd_sem;
 extern struct voyager_status voyager_status;
 extern struct voyager_status voyager_status;
 
 
-
-
 /* functions exported by the voyager and voyager_smp modules */
 /* functions exported by the voyager and voyager_smp modules */
-
 extern int voyager_cat_readb(__u8 module, __u8 asic, int reg);
 extern int voyager_cat_readb(__u8 module, __u8 asic, int reg);
 extern void voyager_cat_init(void);
 extern void voyager_cat_init(void);
 extern void voyager_detect(struct voyager_bios_info *);
 extern void voyager_detect(struct voyager_bios_info *);