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
- Lines: 178
- Date:
Thu Dec 2 19:54:52 1999
- Orig file:
v2.3.29/linux/arch/i386/kernel/smp.c
- Orig date:
Tue Nov 23 22:42:20 1999
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, ¤t->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)