patch-2.3.30 linux/arch/i386/kernel/smp.c

Next file: linux/arch/i386/kernel/smpboot.c
Previous file: linux/arch/i386/kernel/setup.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.29/linux/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c
@@ -102,7 +102,8 @@
 /* The 'big kernel lock' */
 spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
 
-volatile unsigned long smp_invalidate_needed;
+volatile unsigned long smp_invalidate_needed; /* immediate flush required */
+unsigned int cpu_tlbbad[NR_CPUS]; /* flush before returning to user space */
 
 /*
  * the following functions deal with sending IPIs between CPUs.
@@ -319,13 +320,9 @@
 			/*
 			 * Take care of "crossing" invalidates
 			 */
-			if (test_bit(cpu, &smp_invalidate_needed)) {
-				struct mm_struct *mm = current->mm;
-				clear_bit(cpu, &smp_invalidate_needed);
-				if (mm)
-					atomic_set_mask(1 << cpu, &mm->cpu_vm_mask);
-				local_flush_tlb();
-			}
+			if (test_bit(cpu, &smp_invalidate_needed))
+				do_flush_tlb_local();
+
 			--stuck;
 			if (!stuck) {
 				printk("stuck on TLB IPI wait (CPU#%d)\n",cpu);
@@ -345,7 +342,7 @@
  */	
 void flush_tlb_current_task(void)
 {
-	unsigned long vm_mask = 1 << current->processor;
+	unsigned long vm_mask = 1 << smp_processor_id();
 	struct mm_struct *mm = current->mm;
 	unsigned long cpu_mask = mm->cpu_vm_mask & ~vm_mask;
 
@@ -356,7 +353,7 @@
 
 void flush_tlb_mm(struct mm_struct * mm)
 {
-	unsigned long vm_mask = 1 << current->processor;
+	unsigned long vm_mask = 1 << smp_processor_id();
 	unsigned long cpu_mask = mm->cpu_vm_mask & ~vm_mask;
 
 	mm->cpu_vm_mask = 0;
@@ -369,7 +366,7 @@
 
 void flush_tlb_page(struct vm_area_struct * vma, unsigned long va)
 {
-	unsigned long vm_mask = 1 << current->processor;
+	unsigned long vm_mask = 1 << smp_processor_id();
 	struct mm_struct *mm = vma->vm_mm;
 	unsigned long cpu_mask = mm->cpu_vm_mask & ~vm_mask;
 
@@ -381,12 +378,30 @@
 	flush_tlb_others(cpu_mask);
 }
 
-void flush_tlb_all(void)
+static inline void do_flush_tlb_all_local(void)
 {
-	flush_tlb_others(~(1 << current->processor));
 	local_flush_tlb();
+	if (!current->mm && current->active_mm) {
+		unsigned long cpu = smp_processor_id();
+
+		clear_bit(cpu, &current->active_mm->cpu_vm_mask);
+		cpu_tlbbad[cpu] = 1;
+	}
 }
 
+static void flush_tlb_all_ipi(void* info)
+{
+	do_flush_tlb_all_local();
+}
+
+void flush_tlb_all(void)
+{
+	if (cpu_online_map ^ (1 << smp_processor_id()))
+		while (smp_call_function (flush_tlb_all_ipi,0,0,1) == -EBUSY)
+			mb();
+
+	do_flush_tlb_all_local();
+}
 
 /*
  * this function sends a 'reschedule' IPI to another CPU.
@@ -439,9 +454,6 @@
 		if (down_trylock(&lock))
 			return -EBUSY;
 
-	if (call_data) // temporary debugging check
-		BUG();
-
 	call_data = &data;
 	data.func = func;
 	data.info = info;
@@ -478,7 +490,8 @@
 	 * Remove this CPU:
 	 */
 	clear_bit(smp_processor_id(), &cpu_online_map);
-
+	__cli();
+	disable_local_APIC();
 	if (cpu_data[smp_processor_id()].hlt_works_ok)
 		for(;;) __asm__("hlt");
 	for (;;);
@@ -490,7 +503,14 @@
 
 void smp_send_stop(void)
 {
+	unsigned long flags;
+
+	__save_flags(flags);
+	__cli();
         smp_call_function(stop_this_cpu, NULL, 1, 0);
+	disable_local_APIC();
+	__restore_flags(flags);
+
 }
 
 /*
@@ -513,15 +533,9 @@
  */
 asmlinkage void smp_invalidate_interrupt(void)
 {
-	struct task_struct *tsk = current;
-	unsigned int cpu = tsk->processor;
+	if (test_bit(smp_processor_id(), &smp_invalidate_needed))
+		do_flush_tlb_local();
 
-	if (test_and_clear_bit(cpu, &smp_invalidate_needed)) {
-		struct mm_struct *mm = tsk->mm;
-		if (mm)
-			atomic_set_mask(1 << cpu, &mm->cpu_vm_mask);
-		local_flush_tlb();
-	}
 	ack_APIC_irq();
 
 }
@@ -539,7 +553,7 @@
 	 */
 	atomic_inc(&call_data->started);
 	/*
-	 * At this point the structure may be out of scope unless wait==1
+	 * At this point the info structure may be out of scope unless wait==1
 	 */
 	(*func)(info);
 	if (wait)
@@ -575,8 +589,27 @@
 	printk("... APIC ESR0: %08lx\n", v);
 
 	apic_write(APIC_ESR, 0);
-	v = apic_read(APIC_ESR);
+	v |= apic_read(APIC_ESR);
 	printk("... APIC ESR1: %08lx\n", v);
+	/*
+	 * Be a bit more verbose. (multiple bits can be set)
+	 */
+	if (v & 0x01)
+		printk("... bit 0: APIC Send CS Error (hw problem).\n");
+	if (v & 0x02)
+		printk("... bit 1: APIC Receive CS Error (hw problem).\n");
+	if (v & 0x04)
+		printk("... bit 2: APIC Send Accept Error.\n");
+	if (v & 0x08)
+		printk("... bit 3: APIC Receive Accept Error.\n");
+	if (v & 0x10)
+		printk("... bit 4: Reserved!.\n");
+	if (v & 0x20)
+		printk("... bit 5: Send Illegal Vector (kernel bug).\n");
+	if (v & 0x40)
+		printk("... bit 6: Received Illegal Vector.\n");
+	if (v & 0x80)
+		printk("... bit 7: Illegal Register Address.\n");
 
 	ack_APIC_irq();
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)