From: Jun Sun <jsun@mvista.com>
To: Ralf Baechle <ralf@linux-mips.org>
Cc: Juan Quintela <quintela@mandrakesoft.com>,
linux-mips@linux-mips.org, jsun@mvista.com,
Ralf Baechle <ralf@linux-mips.org>
Subject: Re: [RFC & PATCH] fixing tlb flush race problem on smp
Date: Tue, 4 Feb 2003 16:02:50 -0800 [thread overview]
Message-ID: <20030204160250.F5149@mvista.com> (raw)
In-Reply-To: <20030129090627.D7741@linux-mips.org>; from ralf@linux-mips.org on Wed, Jan 29, 2003 at 09:06:27AM +0100
[-- Attachment #1: Type: text/plain, Size: 1364 bytes --]
Here is a complete patch for both mips/mips64, 2.4 and
2.5. Of course only 2.4/mips combo is tested.
The clear_bit/set_bit actually need to be protected.
The flag setting needs to be in sync with the actual
hardware setting (set_entry_hi/set current pgd). Otherwise
an tlb flushing IPI may does the wrong thing.
Jun
On Wed, Jan 29, 2003 at 09:06:27AM +0100, Ralf Baechle wrote:
> On Mon, Jan 27, 2003 at 05:03:46PM -0800, Jun Sun wrote:
>
> > I also find a stupid typo and a subtle hole in my original patch.
> > Here is an updated version, for 2.4/mips only. If it looks ok, I
> > will extend to other sub-arches/trees.
> >
> > This new one is pretty nice in that all mmu related operations
> > are put into one file and it is much easier to ensure correctness
> > later.
>
> I like this one.
>
> > +
> > + /*
> > + * Mark current->active_mm as not "active" anymore.
> > + * We don't want to mislead possible IPI tlb flush routines.
> > + */
> > + clear_bit(cpu, &prev->cpu_vm_mask);
> > + set_bit(cpu, &next->cpu_vm_mask);
> > +
> > + local_irq_restore(flags);
>
> I don't think it's necessary to protect the clear_bit and set_bit operations
> with local_irq_save ... local_irq_restore.
>
> In addition because switch_mm is always called with interrupts enabled you
> can simplify that to local_irq_disable ... local_irq_enable.
>
> Ralf
>
[-- Attachment #2: 030204-2.4-smp-tlb-flush.patch --]
[-- Type: text/plain, Size: 9209 bytes --]
diff -Nru linux/arch/mips/mm/tlb-sb1.c.orig linux/arch/mips/mm/tlb-sb1.c
--- linux/arch/mips/mm/tlb-sb1.c.orig Tue Feb 4 13:50:55 2003
+++ linux/arch/mips/mm/tlb-sb1.c Tue Feb 4 14:01:24 2003
@@ -172,9 +172,7 @@
}
write_c0_entryhi(oldpid);
} else {
- get_new_mmu_context(mm, cpu);
- if (mm == current->active_mm)
- write_c0_entryhi(cpu_asid(cpu, mm));
+ drop_mmu_context(mm, cpu);
}
}
local_irq_restore(flags);
@@ -253,17 +251,10 @@
these entries, we just bump the asid. */
void local_flush_tlb_mm(struct mm_struct *mm)
{
- unsigned long flags;
- int cpu;
- local_irq_save(flags);
- cpu = smp_processor_id();
+ int cpu = smp_processor_id();
if (cpu_context(cpu, mm) != 0) {
- get_new_mmu_context(mm, smp_processor_id());
- if (mm == current->active_mm) {
- write_c0_entryhi(cpu_asid(cpu, mm));
- }
+ drop_mmu_context(mm, cpu);
}
- local_irq_restore(flags);
}
/* Stolen from mips32 routines */
diff -Nru linux/arch/mips/mm/tlb-r4k.c.orig linux/arch/mips/mm/tlb-r4k.c
--- linux/arch/mips/mm/tlb-r4k.c.orig Mon Jan 27 17:13:31 2003
+++ linux/arch/mips/mm/tlb-r4k.c Tue Feb 4 14:15:04 2003
@@ -76,16 +76,10 @@
int cpu = smp_processor_id();
if (cpu_context(cpu, mm) != 0) {
- unsigned long flags;
-
#ifdef DEBUG_TLB
printk("[tlbmm<%d>]", cpu_context(cpu, mm));
#endif
- local_irq_save(flags);
- get_new_mmu_context(mm, smp_processor_id());
- if (mm == current->active_mm)
- write_c0_entryhi(cpu_asid(cpu, mm));
- local_irq_restore(flags);
+ drop_mmu_context(mm,cpu);
}
}
@@ -133,9 +127,7 @@
}
write_c0_entryhi(oldpid);
} else {
- get_new_mmu_context(mm, smp_processor_id());
- if (mm == current->active_mm)
- write_c0_entryhi(cpu_asid(cpu, mm));
+ drop_mmu_context(mm, cpu);
}
local_irq_restore(flags);
}
diff -Nru linux/arch/mips/mm/tlb-r3k.c.orig linux/arch/mips/mm/tlb-r3k.c
--- linux/arch/mips/mm/tlb-r3k.c.orig Mon Jan 27 17:13:31 2003
+++ linux/arch/mips/mm/tlb-r3k.c Tue Feb 4 14:09:04 2003
@@ -69,16 +69,10 @@
int cpu = smp_processor_id();
if (cpu_context(cpu, mm) != 0) {
- unsigned long flags;
-
#ifdef DEBUG_TLB
printk("[tlbmm<%lu>]", (unsigned long)cpu_context(cpu, mm));
#endif
- local_irq_save(flags);
- get_new_mmu_context(mm, smp_processor_id());
- if (mm == current->active_mm)
- write_c0_entryhi(cpu_asid(cpu, mm));
- local_irq_restore(flags);
+ drop_mmu_context(mm, cpu);
}
}
@@ -119,9 +113,7 @@
}
write_c0_entryhi(oldpid);
} else {
- get_new_mmu_context(mm, smp_processor_id());
- if (mm == current->active_mm)
- write_c0_entryhi(cpu_asid(cpu, mm));
+ drop_mmu_context(mm, cpu);
}
local_irq_restore(flags);
}
diff -Nru linux/arch/mips64/mm/tlb-sb1.c.orig linux/arch/mips64/mm/tlb-sb1.c
--- linux/arch/mips64/mm/tlb-sb1.c.orig Mon Jan 27 17:13:34 2003
+++ linux/arch/mips64/mm/tlb-sb1.c Tue Feb 4 14:45:58 2003
@@ -180,9 +180,7 @@
}
write_c0_entryhi(oldpid);
} else {
- get_new_mmu_context(mm, cpu);
- if (mm == current->active_mm)
- write_c0_entryhi(cpu_asid(cpu, mm));
+ drop_mmu_context(mm, cpu);
}
}
local_irq_restore(flags);
@@ -231,17 +229,10 @@
these entries, we just bump the asid. */
void local_flush_tlb_mm(struct mm_struct *mm)
{
- unsigned long flags;
- int cpu;
- local_irq_save(flags);
- cpu = smp_processor_id();
+ int cpu = smp_processor_id();
if (cpu_context(cpu, mm) != 0) {
- get_new_mmu_context(mm, smp_processor_id());
- if (mm == current->active_mm) {
- write_c0_entryhi(cpu_asid(cpu, mm));
- }
+ drop_mmu_context(mm, cpu);
}
- local_irq_restore(flags);
}
/* Stolen from mips32 routines */
diff -Nru linux/arch/mips64/mm/tlb-r4k.c.orig linux/arch/mips64/mm/tlb-r4k.c
--- linux/arch/mips64/mm/tlb-r4k.c.orig Mon Jan 27 17:13:34 2003
+++ linux/arch/mips64/mm/tlb-r4k.c Tue Feb 4 14:47:52 2003
@@ -80,16 +80,10 @@
int cpu = smp_processor_id();
if (cpu_context(cpu, mm) != 0) {
- unsigned long flags;
-
#ifdef DEBUG_TLB
printk("[tlbmm<%d>]", mm->context);
#endif
- local_irq_save(flags);
- get_new_mmu_context(mm, cpu);
- if (mm == current->active_mm)
- write_c0_entryhi(cpu_asid(cpu, mm));
- local_irq_restore(flags);
+ drop_mmu_context(mm,cpu);
}
}
@@ -137,9 +131,7 @@
}
write_c0_entryhi(oldpid);
} else {
- get_new_mmu_context(mm, cpu);
- if (mm == current->active_mm)
- write_c0_entryhi(cpu_asid(cpu, mm));
+ drop_mmu_context(mm, cpu);
}
local_irq_restore(flags);
}
diff -Nru linux/arch/mips64/mm/tlb-andes.c.orig linux/arch/mips64/mm/tlb-andes.c
--- linux/arch/mips64/mm/tlb-andes.c.orig Tue Feb 4 13:13:43 2003
+++ linux/arch/mips64/mm/tlb-andes.c Tue Feb 4 14:49:59 2003
@@ -53,18 +53,12 @@
void local_flush_tlb_mm(struct mm_struct *mm)
{
- if (cpu_context(smp_processor_id(), mm) != 0) {
- unsigned long flags;
-
+ int cpu = smp_processor_id();
+ if (cpu_context(cpu, mm) != 0) {
#ifdef DEBUG_TLB
printk("[tlbmm<%d>]", mm->context);
#endif
- local_irq_save(flags);
- get_new_mmu_context(mm, smp_processor_id());
- if (mm == current->active_mm)
- write_c0_entryhi(cpu_context(smp_processor_id(), mm)
- & ASID_MASK);
- local_irq_restore(flags);
+ drop_mmu_context(mm,cpu);
}
}
@@ -106,10 +100,7 @@
}
write_c0_entryhi(oldpid);
} else {
- get_new_mmu_context(mm, smp_processor_id());
- if (mm == current->active_mm)
- write_c0_entryhi(cpu_context(smp_processor_id(), mm)
- & ASID_MASK);
+ drop_mmu_context(mm, cpu);
}
local_irq_restore(flags);
}
diff -Nru linux/include/asm-mips/mmu_context.h.orig linux/include/asm-mips/mmu_context.h
--- linux/include/asm-mips/mmu_context.h.orig Tue Feb 4 13:50:55 2003
+++ linux/include/asm-mips/mmu_context.h Tue Feb 4 13:51:03 2003
@@ -89,12 +89,25 @@
static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
struct task_struct *tsk, unsigned cpu)
{
+ unsigned long flags;
+
+ local_irq_save(flags);
+
/* Check if our ASID is of an older version and thus invalid */
if ((cpu_context(cpu, next) ^ asid_cache(cpu)) & ASID_VERSION_MASK)
get_new_mmu_context(next, cpu);
write_c0_entryhi(cpu_context(cpu, next));
TLBMISS_HANDLER_SETUP_PGD(next->pgd);
+
+ /*
+ * Mark current->active_mm as not "active" anymore.
+ * We don't want to mislead possible IPI tlb flush routines.
+ */
+ clear_bit(cpu, &prev->cpu_vm_mask);
+ set_bit(cpu, &next->cpu_vm_mask);
+
+ local_irq_restore(flags);
}
/*
@@ -112,11 +125,39 @@
static inline void
activate_mm(struct mm_struct *prev, struct mm_struct *next)
{
+ unsigned long flags;
+
+ local_irq_save(flags);
+
/* Unconditionally get a new ASID. */
get_new_mmu_context(next, smp_processor_id());
write_c0_entryhi(cpu_context(smp_processor_id(), next));
TLBMISS_HANDLER_SETUP_PGD(next->pgd);
+
+ local_irq_restore(flags);
+}
+
+/*
+ * If mm is currently active_mm, we can't really drop it. Instead,
+ * we will get a new one for it.
+ */
+static inline void
+drop_mmu_context(struct mm_struct *mm, unsigned cpu)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ if (test_bit(cpu, &mm->cpu_vm_mask)) {
+ get_new_mmu_context(mm, cpu);
+ set_entryhi(CPU_CONTEXT(cpu, mm) & 0xff);
+ } else {
+ /* will get a new context next time */
+ CPU_CONTEXT(cpu, mm) = 0;
+ }
+
+ local_irq_restore(flags);
}
#endif /* _ASM_MMU_CONTEXT_H */
diff -Nru linux/include/asm-mips64/mmu_context.h.orig linux/include/asm-mips64/mmu_context.h
--- linux/include/asm-mips64/mmu_context.h.orig Tue Jan 21 13:55:43 2003
+++ linux/include/asm-mips64/mmu_context.h Tue Feb 4 14:46:00 2003
@@ -80,12 +80,25 @@
static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
struct task_struct *tsk, unsigned cpu)
{
+ unsigned long flags;
+
+ local_irq_save(flags);
+
/* Check if our ASID is of an older version and thus invalid */
if ((cpu_context(cpu, next) ^ asid_cache(cpu)) & ASID_VERSION_MASK)
get_new_mmu_context(next, cpu);
write_c0_entryhi(cpu_context(cpu, next));
TLBMISS_HANDLER_SETUP_PGD(next->pgd);
+
+ /*
+ * Mark current->active_mm as not "active" anymore.
+ * We don't want to mislead possible IPI tlb flush routines.
+ */
+ clear_bit(cpu, &prev->cpu_vm_mask);
+ set_bit(cpu, &next->cpu_vm_mask);
+
+ local_irq_restore(flags);
}
/*
@@ -103,11 +116,39 @@
static inline void
activate_mm(struct mm_struct *prev, struct mm_struct *next)
{
+ unsigned long flags;
+
+ local_irq_save(flags);
+
/* Unconditionally get a new ASID. */
get_new_mmu_context(next, smp_processor_id());
write_c0_entryhi(cpu_context(smp_processor_id(), next));
TLBMISS_HANDLER_SETUP_PGD(next->pgd);
+
+ local_irq_restore(flags);
+}
+
+/*
+ * If mm is currently active_mm, we can't really drop it. Instead,
+ * we will get a new one for it.
+ */
+static inline void
+drop_mmu_context(struct mm_struct *mm, unsigned cpu)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ if (test_bit(cpu, &mm->cpu_vm_mask)) {
+ get_new_mmu_context(mm, cpu);
+ set_entryhi(CPU_CONTEXT(cpu, mm) & 0xff);
+ } else {
+ /* will get a new context next time */
+ CPU_CONTEXT(cpu, mm) = 0;
+ }
+
+ local_irq_restore(flags);
}
#endif /* _ASM_MMU_CONTEXT_H */
[-- Attachment #3: 030204-2.5-smp-tlb-flush.patch --]
[-- Type: text/plain, Size: 9558 bytes --]
diff -Nru linux/arch/mips/mm/tlb-sb1.c.orig linux/arch/mips/mm/tlb-sb1.c
--- linux/arch/mips/mm/tlb-sb1.c.orig Wed Dec 11 17:04:17 2002
+++ linux/arch/mips/mm/tlb-sb1.c Tue Feb 4 15:00:53 2003
@@ -172,15 +172,7 @@
}
write_c0_entryhi(oldpid);
} else {
- get_new_mmu_context(mm, cpu);
- if (mm == current->active_mm) {
- write_c0_entryhi(cpu_asid(cpu, mm));
- } else if (!(cpu_asid(cpu, mm)) &&
- cpu_context(cpu, current->active_mm)) {
- /* Just wrapped ASIDs, bump the active one */
- get_new_mmu_context(current->active_mm, cpu);
- write_c0_entryhi(cpu_context(cpu, current->active_mm)& 0xff);
- }
+ drop_mmu_context(mm, cpu);
}
}
local_irq_restore(flags);
@@ -325,17 +317,10 @@
these entries, we just bump the asid. */
void local_flush_tlb_mm(struct mm_struct *mm)
{
- unsigned long flags;
- int cpu;
- local_irq_save(flags);
- cpu = smp_processor_id();
+ int cpu = smp_processor_id();
if (cpu_context(cpu, mm) != 0) {
- get_new_mmu_context(mm, smp_processor_id());
- if (mm == current->active_mm) {
- write_c0_entryhi(cpu_context(cpu, mm) & 0xff);
- }
+ drop_mmu_context(mm, cpu);
}
- local_irq_restore(flags);
}
/* Stolen from mips32 routines */
diff -Nru linux/arch/mips/mm/tlb-r4k.c.orig linux/arch/mips/mm/tlb-r4k.c
--- linux/arch/mips/mm/tlb-r4k.c.orig Mon Jan 27 18:03:21 2003
+++ linux/arch/mips/mm/tlb-r4k.c Tue Feb 4 15:04:29 2003
@@ -76,16 +76,10 @@
int cpu = smp_processor_id();
if (cpu_context(cpu, mm) != 0) {
- unsigned long flags;
-
#ifdef DEBUG_TLB
printk("[tlbmm<%d>]", cpu_context(cpu, mm));
#endif
- local_irq_save(flags);
- get_new_mmu_context(mm, smp_processor_id());
- if (mm == current->active_mm)
- write_c0_entryhi(cpu_context(cpu, mm) & ASID_MASK);
- local_irq_restore(flags);
+ drop_mmu_context(mm,cpu);
}
}
@@ -134,9 +128,7 @@
}
write_c0_entryhi(oldpid);
} else {
- get_new_mmu_context(mm, smp_processor_id());
- if (mm == current->active_mm)
- write_c0_entryhi(cpu_context(cpu, mm) & ASID_MASK);
+ drop_mmu_context(mm, cpu);
}
local_irq_restore(flags);
}
diff -Nru linux/arch/mips/mm/tlb-r3k.c.orig linux/arch/mips/mm/tlb-r3k.c
--- linux/arch/mips/mm/tlb-r3k.c.orig Mon Jan 27 18:03:21 2003
+++ linux/arch/mips/mm/tlb-r3k.c Tue Feb 4 15:05:22 2003
@@ -69,16 +69,10 @@
int cpu = smp_processor_id();
if (cpu_context(cpu, mm) != 0) {
- unsigned long flags;
-
#ifdef DEBUG_TLB
printk("[tlbmm<%lu>]", (unsigned long)cpu_context(cpu, mm));
#endif
- local_irq_save(flags);
- get_new_mmu_context(mm, cpu);
- if (mm == current->active_mm)
- write_c0_entryhi(cpu_context(cpu, mm) & ASID_MASK);
- local_irq_restore(flags);
+ drop_mmu_context(mm, cpu);
}
}
@@ -120,9 +114,7 @@
}
write_c0_entryhi(oldpid);
} else {
- get_new_mmu_context(mm, smp_processor_id());
- if (mm == current->active_mm)
- write_c0_entryhi(cpu_context(cpu, mm) & ASID_MASK);
+ drop_mmu_context(mm, cpu);
}
local_irq_restore(flags);
}
diff -Nru linux/arch/mips64/mm/tlb-sb1.c.orig linux/arch/mips64/mm/tlb-sb1.c
--- linux/arch/mips64/mm/tlb-sb1.c.orig Wed Dec 11 17:04:19 2002
+++ linux/arch/mips64/mm/tlb-sb1.c Tue Feb 4 15:07:42 2003
@@ -180,9 +180,7 @@
}
write_c0_entryhi(oldpid);
} else {
- get_new_mmu_context(mm, cpu);
- if (mm == current->active_mm)
- write_c0_entryhi(cpu_context(cpu, mm) & 0xff);
+ drop_mmu_context(mm, cpu);
}
}
local_irq_restore(flags);
@@ -268,17 +266,10 @@
these entries, we just bump the asid. */
void local_flush_tlb_mm(struct mm_struct *mm)
{
- unsigned long flags;
- int cpu;
- local_irq_save(flags);
- cpu = smp_processor_id();
+ int cpu = smp_processor_id();
if (cpu_context(cpu, mm) != 0) {
- get_new_mmu_context(mm, smp_processor_id());
- if (mm == current->active_mm) {
- write_c0_entryhi(cpu_context(cpu, mm) & 0xff);
- }
+ drop_mmu_context(mm, cpu);
}
- local_irq_restore(flags);
}
/* Stolen from mips32 routines */
diff -Nru linux/arch/mips64/mm/tlb-r4k.c.orig linux/arch/mips64/mm/tlb-r4k.c
--- linux/arch/mips64/mm/tlb-r4k.c.orig Mon Jan 27 18:03:22 2003
+++ linux/arch/mips64/mm/tlb-r4k.c Tue Feb 4 15:08:21 2003
@@ -80,16 +80,10 @@
int cpu = smp_processor_id();
if (cpu_context(cpu, mm) != 0) {
- unsigned long flags;
-
#ifdef DEBUG_TLB
printk("[tlbmm<%d>]", cpu_context(cpu, mm));
#endif
- local_irq_save(flags);
- get_new_mmu_context(mm, cpu);
- if (mm == current->active_mm)
- write_c0_entryhi(cpu_asid(cpu, mm));
- local_irq_restore(flags);
+ drop_mmu_context(mm,cpu);
}
}
@@ -138,9 +132,7 @@
}
write_c0_entryhi(oldpid);
} else {
- get_new_mmu_context(mm, cpu);
- if (mm == current->active_mm)
- write_c0_entryhi(cpu_asid(cpu, mm));
+ drop_mmu_context(mm, cpu);
}
local_irq_restore(flags);
}
diff -Nru linux/arch/mips64/mm/tlb-andes.c.orig linux/arch/mips64/mm/tlb-andes.c
--- linux/arch/mips64/mm/tlb-andes.c.orig Tue Feb 4 13:14:43 2003
+++ linux/arch/mips64/mm/tlb-andes.c Tue Feb 4 14:53:28 2003
@@ -53,18 +53,12 @@
void local_flush_tlb_mm(struct mm_struct *mm)
{
- if (cpu_context(smp_processor_id(), mm) != 0) {
- unsigned long flags;
-
+ int cpu = smp_processor_id();
+ if (cpu_context(cpu, mm) != 0) {
#ifdef DEBUG_TLB
printk("[tlbmm<%d>]", mm->context);
#endif
- local_irq_save(flags);
- get_new_mmu_context(mm, smp_processor_id());
- if (mm == current->active_mm)
- write_c0_entryhi(cpu_context(smp_processor_id(), mm)
- & ASID_MASK);
- local_irq_restore(flags);
+ drop_mmu_context(mm,cpu);
}
}
@@ -108,10 +102,7 @@
}
write_c0_entryhi(oldpid);
} else {
- get_new_mmu_context(mm, smp_processor_id());
- if (mm == current->active_mm)
- write_c0_entryhi(cpu_context(smp_processor_id(), mm)
- & ASID_MASK);
+ drop_mmu_context(mm, cpu);
}
local_irq_restore(flags);
}
diff -Nru linux/include/asm-mips/mmu_context.h.orig linux/include/asm-mips/mmu_context.h
--- linux/include/asm-mips/mmu_context.h.orig Mon Jan 27 18:03:23 2003
+++ linux/include/asm-mips/mmu_context.h Tue Feb 4 14:53:28 2003
@@ -92,12 +92,25 @@
static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
struct task_struct *tsk, unsigned cpu)
{
+ unsigned long flags;
+
+ local_irq_save(flags);
+
/* Check if our ASID is of an older version and thus invalid */
if ((cpu_context(cpu, next) ^ asid_cache(cpu)) & ASID_VERSION_MASK)
get_new_mmu_context(next, cpu);
write_c0_entryhi(cpu_context(cpu, next));
TLBMISS_HANDLER_SETUP_PGD(next->pgd);
+
+ /*
+ * Mark current->active_mm as not "active" anymore.
+ * We don't want to mislead possible IPI tlb flush routines.
+ */
+ clear_bit(cpu, &prev->cpu_vm_mask);
+ set_bit(cpu, &next->cpu_vm_mask);
+
+ local_irq_restore(flags);
}
/*
@@ -115,11 +128,39 @@
static inline void
activate_mm(struct mm_struct *prev, struct mm_struct *next)
{
+ unsigned long flags;
+
+ local_irq_save(flags);
+
/* Unconditionally get a new ASID. */
get_new_mmu_context(next, smp_processor_id());
write_c0_entryhi(cpu_context(smp_processor_id(), next));
TLBMISS_HANDLER_SETUP_PGD(next->pgd);
+
+ local_irq_restore(flags);
+}
+
+/*
+ * If mm is currently active_mm, we can't really drop it. Instead,
+ * we will get a new one for it.
+ */
+static inline void
+drop_mmu_context(struct mm_struct *mm, unsigned cpu)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ if (test_bit(cpu, &mm->cpu_vm_mask)) {
+ get_new_mmu_context(mm, cpu);
+ set_entryhi(CPU_CONTEXT(cpu, mm) & 0xff);
+ } else {
+ /* will get a new context next time */
+ CPU_CONTEXT(cpu, mm) = 0;
+ }
+
+ local_irq_restore(flags);
}
#endif /* _ASM_MMU_CONTEXT_H */
diff -Nru linux/include/asm-mips64/mmu_context.h.orig linux/include/asm-mips64/mmu_context.h
--- linux/include/asm-mips64/mmu_context.h.orig Mon Jan 27 18:03:23 2003
+++ linux/include/asm-mips64/mmu_context.h Tue Feb 4 14:53:28 2003
@@ -83,12 +83,25 @@
static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
struct task_struct *tsk, unsigned cpu)
{
+ unsigned long flags;
+
+ local_irq_save(flags);
+
/* Check if our ASID is of an older version and thus invalid */
if ((cpu_context(cpu, next) ^ asid_cache(cpu)) & ASID_VERSION_MASK)
get_new_mmu_context(next, cpu);
write_c0_entryhi(cpu_context(cpu, next));
TLBMISS_HANDLER_SETUP_PGD(next->pgd);
+
+ /*
+ * Mark current->active_mm as not "active" anymore.
+ * We don't want to mislead possible IPI tlb flush routines.
+ */
+ clear_bit(cpu, &prev->cpu_vm_mask);
+ set_bit(cpu, &next->cpu_vm_mask);
+
+ local_irq_restore(flags);
}
/*
@@ -106,11 +119,39 @@
static inline void
activate_mm(struct mm_struct *prev, struct mm_struct *next)
{
+ unsigned long flags;
+
+ local_irq_save(flags);
+
/* Unconditionally get a new ASID. */
get_new_mmu_context(next, smp_processor_id());
write_c0_entryhi(cpu_context(smp_processor_id(), next));
TLBMISS_HANDLER_SETUP_PGD(next->pgd);
+
+ local_irq_restore(flags);
+}
+
+/*
+ * If mm is currently active_mm, we can't really drop it. Instead,
+ * we will get a new one for it.
+ */
+static inline void
+drop_mmu_context(struct mm_struct *mm, unsigned cpu)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ if (test_bit(cpu, &mm->cpu_vm_mask)) {
+ get_new_mmu_context(mm, cpu);
+ set_entryhi(CPU_CONTEXT(cpu, mm) & 0xff);
+ } else {
+ /* will get a new context next time */
+ CPU_CONTEXT(cpu, mm) = 0;
+ }
+
+ local_irq_restore(flags);
}
#endif /* _ASM_MMU_CONTEXT_H */
WARNING: multiple messages have this Message-ID (diff)
From: Jun Sun <jsun@mvista.com>
To: Ralf Baechle <ralf@linux-mips.org>
Cc: Juan Quintela <quintela@mandrakesoft.com>,
linux-mips@linux-mips.org, jsun@mvista.com
Subject: Re: [RFC & PATCH] fixing tlb flush race problem on smp
Date: Tue, 4 Feb 2003 16:02:50 -0800 [thread overview]
Message-ID: <20030204160250.F5149@mvista.com> (raw)
Message-ID: <20030205000250.zB-1c51EfXDYMlHeQuUD9QShhqkaT3guI-3jPXYuRR8@z> (raw)
In-Reply-To: <20030129090627.D7741@linux-mips.org>; from ralf@linux-mips.org on Wed, Jan 29, 2003 at 09:06:27AM +0100
[-- Attachment #1: Type: text/plain, Size: 1364 bytes --]
Here is a complete patch for both mips/mips64, 2.4 and
2.5. Of course only 2.4/mips combo is tested.
The clear_bit/set_bit actually need to be protected.
The flag setting needs to be in sync with the actual
hardware setting (set_entry_hi/set current pgd). Otherwise
an tlb flushing IPI may does the wrong thing.
Jun
On Wed, Jan 29, 2003 at 09:06:27AM +0100, Ralf Baechle wrote:
> On Mon, Jan 27, 2003 at 05:03:46PM -0800, Jun Sun wrote:
>
> > I also find a stupid typo and a subtle hole in my original patch.
> > Here is an updated version, for 2.4/mips only. If it looks ok, I
> > will extend to other sub-arches/trees.
> >
> > This new one is pretty nice in that all mmu related operations
> > are put into one file and it is much easier to ensure correctness
> > later.
>
> I like this one.
>
> > +
> > + /*
> > + * Mark current->active_mm as not "active" anymore.
> > + * We don't want to mislead possible IPI tlb flush routines.
> > + */
> > + clear_bit(cpu, &prev->cpu_vm_mask);
> > + set_bit(cpu, &next->cpu_vm_mask);
> > +
> > + local_irq_restore(flags);
>
> I don't think it's necessary to protect the clear_bit and set_bit operations
> with local_irq_save ... local_irq_restore.
>
> In addition because switch_mm is always called with interrupts enabled you
> can simplify that to local_irq_disable ... local_irq_enable.
>
> Ralf
>
[-- Attachment #2: 030204-2.4-smp-tlb-flush.patch --]
[-- Type: text/plain, Size: 9209 bytes --]
diff -Nru linux/arch/mips/mm/tlb-sb1.c.orig linux/arch/mips/mm/tlb-sb1.c
--- linux/arch/mips/mm/tlb-sb1.c.orig Tue Feb 4 13:50:55 2003
+++ linux/arch/mips/mm/tlb-sb1.c Tue Feb 4 14:01:24 2003
@@ -172,9 +172,7 @@
}
write_c0_entryhi(oldpid);
} else {
- get_new_mmu_context(mm, cpu);
- if (mm == current->active_mm)
- write_c0_entryhi(cpu_asid(cpu, mm));
+ drop_mmu_context(mm, cpu);
}
}
local_irq_restore(flags);
@@ -253,17 +251,10 @@
these entries, we just bump the asid. */
void local_flush_tlb_mm(struct mm_struct *mm)
{
- unsigned long flags;
- int cpu;
- local_irq_save(flags);
- cpu = smp_processor_id();
+ int cpu = smp_processor_id();
if (cpu_context(cpu, mm) != 0) {
- get_new_mmu_context(mm, smp_processor_id());
- if (mm == current->active_mm) {
- write_c0_entryhi(cpu_asid(cpu, mm));
- }
+ drop_mmu_context(mm, cpu);
}
- local_irq_restore(flags);
}
/* Stolen from mips32 routines */
diff -Nru linux/arch/mips/mm/tlb-r4k.c.orig linux/arch/mips/mm/tlb-r4k.c
--- linux/arch/mips/mm/tlb-r4k.c.orig Mon Jan 27 17:13:31 2003
+++ linux/arch/mips/mm/tlb-r4k.c Tue Feb 4 14:15:04 2003
@@ -76,16 +76,10 @@
int cpu = smp_processor_id();
if (cpu_context(cpu, mm) != 0) {
- unsigned long flags;
-
#ifdef DEBUG_TLB
printk("[tlbmm<%d>]", cpu_context(cpu, mm));
#endif
- local_irq_save(flags);
- get_new_mmu_context(mm, smp_processor_id());
- if (mm == current->active_mm)
- write_c0_entryhi(cpu_asid(cpu, mm));
- local_irq_restore(flags);
+ drop_mmu_context(mm,cpu);
}
}
@@ -133,9 +127,7 @@
}
write_c0_entryhi(oldpid);
} else {
- get_new_mmu_context(mm, smp_processor_id());
- if (mm == current->active_mm)
- write_c0_entryhi(cpu_asid(cpu, mm));
+ drop_mmu_context(mm, cpu);
}
local_irq_restore(flags);
}
diff -Nru linux/arch/mips/mm/tlb-r3k.c.orig linux/arch/mips/mm/tlb-r3k.c
--- linux/arch/mips/mm/tlb-r3k.c.orig Mon Jan 27 17:13:31 2003
+++ linux/arch/mips/mm/tlb-r3k.c Tue Feb 4 14:09:04 2003
@@ -69,16 +69,10 @@
int cpu = smp_processor_id();
if (cpu_context(cpu, mm) != 0) {
- unsigned long flags;
-
#ifdef DEBUG_TLB
printk("[tlbmm<%lu>]", (unsigned long)cpu_context(cpu, mm));
#endif
- local_irq_save(flags);
- get_new_mmu_context(mm, smp_processor_id());
- if (mm == current->active_mm)
- write_c0_entryhi(cpu_asid(cpu, mm));
- local_irq_restore(flags);
+ drop_mmu_context(mm, cpu);
}
}
@@ -119,9 +113,7 @@
}
write_c0_entryhi(oldpid);
} else {
- get_new_mmu_context(mm, smp_processor_id());
- if (mm == current->active_mm)
- write_c0_entryhi(cpu_asid(cpu, mm));
+ drop_mmu_context(mm, cpu);
}
local_irq_restore(flags);
}
diff -Nru linux/arch/mips64/mm/tlb-sb1.c.orig linux/arch/mips64/mm/tlb-sb1.c
--- linux/arch/mips64/mm/tlb-sb1.c.orig Mon Jan 27 17:13:34 2003
+++ linux/arch/mips64/mm/tlb-sb1.c Tue Feb 4 14:45:58 2003
@@ -180,9 +180,7 @@
}
write_c0_entryhi(oldpid);
} else {
- get_new_mmu_context(mm, cpu);
- if (mm == current->active_mm)
- write_c0_entryhi(cpu_asid(cpu, mm));
+ drop_mmu_context(mm, cpu);
}
}
local_irq_restore(flags);
@@ -231,17 +229,10 @@
these entries, we just bump the asid. */
void local_flush_tlb_mm(struct mm_struct *mm)
{
- unsigned long flags;
- int cpu;
- local_irq_save(flags);
- cpu = smp_processor_id();
+ int cpu = smp_processor_id();
if (cpu_context(cpu, mm) != 0) {
- get_new_mmu_context(mm, smp_processor_id());
- if (mm == current->active_mm) {
- write_c0_entryhi(cpu_asid(cpu, mm));
- }
+ drop_mmu_context(mm, cpu);
}
- local_irq_restore(flags);
}
/* Stolen from mips32 routines */
diff -Nru linux/arch/mips64/mm/tlb-r4k.c.orig linux/arch/mips64/mm/tlb-r4k.c
--- linux/arch/mips64/mm/tlb-r4k.c.orig Mon Jan 27 17:13:34 2003
+++ linux/arch/mips64/mm/tlb-r4k.c Tue Feb 4 14:47:52 2003
@@ -80,16 +80,10 @@
int cpu = smp_processor_id();
if (cpu_context(cpu, mm) != 0) {
- unsigned long flags;
-
#ifdef DEBUG_TLB
printk("[tlbmm<%d>]", mm->context);
#endif
- local_irq_save(flags);
- get_new_mmu_context(mm, cpu);
- if (mm == current->active_mm)
- write_c0_entryhi(cpu_asid(cpu, mm));
- local_irq_restore(flags);
+ drop_mmu_context(mm,cpu);
}
}
@@ -137,9 +131,7 @@
}
write_c0_entryhi(oldpid);
} else {
- get_new_mmu_context(mm, cpu);
- if (mm == current->active_mm)
- write_c0_entryhi(cpu_asid(cpu, mm));
+ drop_mmu_context(mm, cpu);
}
local_irq_restore(flags);
}
diff -Nru linux/arch/mips64/mm/tlb-andes.c.orig linux/arch/mips64/mm/tlb-andes.c
--- linux/arch/mips64/mm/tlb-andes.c.orig Tue Feb 4 13:13:43 2003
+++ linux/arch/mips64/mm/tlb-andes.c Tue Feb 4 14:49:59 2003
@@ -53,18 +53,12 @@
void local_flush_tlb_mm(struct mm_struct *mm)
{
- if (cpu_context(smp_processor_id(), mm) != 0) {
- unsigned long flags;
-
+ int cpu = smp_processor_id();
+ if (cpu_context(cpu, mm) != 0) {
#ifdef DEBUG_TLB
printk("[tlbmm<%d>]", mm->context);
#endif
- local_irq_save(flags);
- get_new_mmu_context(mm, smp_processor_id());
- if (mm == current->active_mm)
- write_c0_entryhi(cpu_context(smp_processor_id(), mm)
- & ASID_MASK);
- local_irq_restore(flags);
+ drop_mmu_context(mm,cpu);
}
}
@@ -106,10 +100,7 @@
}
write_c0_entryhi(oldpid);
} else {
- get_new_mmu_context(mm, smp_processor_id());
- if (mm == current->active_mm)
- write_c0_entryhi(cpu_context(smp_processor_id(), mm)
- & ASID_MASK);
+ drop_mmu_context(mm, cpu);
}
local_irq_restore(flags);
}
diff -Nru linux/include/asm-mips/mmu_context.h.orig linux/include/asm-mips/mmu_context.h
--- linux/include/asm-mips/mmu_context.h.orig Tue Feb 4 13:50:55 2003
+++ linux/include/asm-mips/mmu_context.h Tue Feb 4 13:51:03 2003
@@ -89,12 +89,25 @@
static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
struct task_struct *tsk, unsigned cpu)
{
+ unsigned long flags;
+
+ local_irq_save(flags);
+
/* Check if our ASID is of an older version and thus invalid */
if ((cpu_context(cpu, next) ^ asid_cache(cpu)) & ASID_VERSION_MASK)
get_new_mmu_context(next, cpu);
write_c0_entryhi(cpu_context(cpu, next));
TLBMISS_HANDLER_SETUP_PGD(next->pgd);
+
+ /*
+ * Mark current->active_mm as not "active" anymore.
+ * We don't want to mislead possible IPI tlb flush routines.
+ */
+ clear_bit(cpu, &prev->cpu_vm_mask);
+ set_bit(cpu, &next->cpu_vm_mask);
+
+ local_irq_restore(flags);
}
/*
@@ -112,11 +125,39 @@
static inline void
activate_mm(struct mm_struct *prev, struct mm_struct *next)
{
+ unsigned long flags;
+
+ local_irq_save(flags);
+
/* Unconditionally get a new ASID. */
get_new_mmu_context(next, smp_processor_id());
write_c0_entryhi(cpu_context(smp_processor_id(), next));
TLBMISS_HANDLER_SETUP_PGD(next->pgd);
+
+ local_irq_restore(flags);
+}
+
+/*
+ * If mm is currently active_mm, we can't really drop it. Instead,
+ * we will get a new one for it.
+ */
+static inline void
+drop_mmu_context(struct mm_struct *mm, unsigned cpu)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ if (test_bit(cpu, &mm->cpu_vm_mask)) {
+ get_new_mmu_context(mm, cpu);
+ set_entryhi(CPU_CONTEXT(cpu, mm) & 0xff);
+ } else {
+ /* will get a new context next time */
+ CPU_CONTEXT(cpu, mm) = 0;
+ }
+
+ local_irq_restore(flags);
}
#endif /* _ASM_MMU_CONTEXT_H */
diff -Nru linux/include/asm-mips64/mmu_context.h.orig linux/include/asm-mips64/mmu_context.h
--- linux/include/asm-mips64/mmu_context.h.orig Tue Jan 21 13:55:43 2003
+++ linux/include/asm-mips64/mmu_context.h Tue Feb 4 14:46:00 2003
@@ -80,12 +80,25 @@
static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
struct task_struct *tsk, unsigned cpu)
{
+ unsigned long flags;
+
+ local_irq_save(flags);
+
/* Check if our ASID is of an older version and thus invalid */
if ((cpu_context(cpu, next) ^ asid_cache(cpu)) & ASID_VERSION_MASK)
get_new_mmu_context(next, cpu);
write_c0_entryhi(cpu_context(cpu, next));
TLBMISS_HANDLER_SETUP_PGD(next->pgd);
+
+ /*
+ * Mark current->active_mm as not "active" anymore.
+ * We don't want to mislead possible IPI tlb flush routines.
+ */
+ clear_bit(cpu, &prev->cpu_vm_mask);
+ set_bit(cpu, &next->cpu_vm_mask);
+
+ local_irq_restore(flags);
}
/*
@@ -103,11 +116,39 @@
static inline void
activate_mm(struct mm_struct *prev, struct mm_struct *next)
{
+ unsigned long flags;
+
+ local_irq_save(flags);
+
/* Unconditionally get a new ASID. */
get_new_mmu_context(next, smp_processor_id());
write_c0_entryhi(cpu_context(smp_processor_id(), next));
TLBMISS_HANDLER_SETUP_PGD(next->pgd);
+
+ local_irq_restore(flags);
+}
+
+/*
+ * If mm is currently active_mm, we can't really drop it. Instead,
+ * we will get a new one for it.
+ */
+static inline void
+drop_mmu_context(struct mm_struct *mm, unsigned cpu)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ if (test_bit(cpu, &mm->cpu_vm_mask)) {
+ get_new_mmu_context(mm, cpu);
+ set_entryhi(CPU_CONTEXT(cpu, mm) & 0xff);
+ } else {
+ /* will get a new context next time */
+ CPU_CONTEXT(cpu, mm) = 0;
+ }
+
+ local_irq_restore(flags);
}
#endif /* _ASM_MMU_CONTEXT_H */
[-- Attachment #3: 030204-2.5-smp-tlb-flush.patch --]
[-- Type: text/plain, Size: 9558 bytes --]
diff -Nru linux/arch/mips/mm/tlb-sb1.c.orig linux/arch/mips/mm/tlb-sb1.c
--- linux/arch/mips/mm/tlb-sb1.c.orig Wed Dec 11 17:04:17 2002
+++ linux/arch/mips/mm/tlb-sb1.c Tue Feb 4 15:00:53 2003
@@ -172,15 +172,7 @@
}
write_c0_entryhi(oldpid);
} else {
- get_new_mmu_context(mm, cpu);
- if (mm == current->active_mm) {
- write_c0_entryhi(cpu_asid(cpu, mm));
- } else if (!(cpu_asid(cpu, mm)) &&
- cpu_context(cpu, current->active_mm)) {
- /* Just wrapped ASIDs, bump the active one */
- get_new_mmu_context(current->active_mm, cpu);
- write_c0_entryhi(cpu_context(cpu, current->active_mm)& 0xff);
- }
+ drop_mmu_context(mm, cpu);
}
}
local_irq_restore(flags);
@@ -325,17 +317,10 @@
these entries, we just bump the asid. */
void local_flush_tlb_mm(struct mm_struct *mm)
{
- unsigned long flags;
- int cpu;
- local_irq_save(flags);
- cpu = smp_processor_id();
+ int cpu = smp_processor_id();
if (cpu_context(cpu, mm) != 0) {
- get_new_mmu_context(mm, smp_processor_id());
- if (mm == current->active_mm) {
- write_c0_entryhi(cpu_context(cpu, mm) & 0xff);
- }
+ drop_mmu_context(mm, cpu);
}
- local_irq_restore(flags);
}
/* Stolen from mips32 routines */
diff -Nru linux/arch/mips/mm/tlb-r4k.c.orig linux/arch/mips/mm/tlb-r4k.c
--- linux/arch/mips/mm/tlb-r4k.c.orig Mon Jan 27 18:03:21 2003
+++ linux/arch/mips/mm/tlb-r4k.c Tue Feb 4 15:04:29 2003
@@ -76,16 +76,10 @@
int cpu = smp_processor_id();
if (cpu_context(cpu, mm) != 0) {
- unsigned long flags;
-
#ifdef DEBUG_TLB
printk("[tlbmm<%d>]", cpu_context(cpu, mm));
#endif
- local_irq_save(flags);
- get_new_mmu_context(mm, smp_processor_id());
- if (mm == current->active_mm)
- write_c0_entryhi(cpu_context(cpu, mm) & ASID_MASK);
- local_irq_restore(flags);
+ drop_mmu_context(mm,cpu);
}
}
@@ -134,9 +128,7 @@
}
write_c0_entryhi(oldpid);
} else {
- get_new_mmu_context(mm, smp_processor_id());
- if (mm == current->active_mm)
- write_c0_entryhi(cpu_context(cpu, mm) & ASID_MASK);
+ drop_mmu_context(mm, cpu);
}
local_irq_restore(flags);
}
diff -Nru linux/arch/mips/mm/tlb-r3k.c.orig linux/arch/mips/mm/tlb-r3k.c
--- linux/arch/mips/mm/tlb-r3k.c.orig Mon Jan 27 18:03:21 2003
+++ linux/arch/mips/mm/tlb-r3k.c Tue Feb 4 15:05:22 2003
@@ -69,16 +69,10 @@
int cpu = smp_processor_id();
if (cpu_context(cpu, mm) != 0) {
- unsigned long flags;
-
#ifdef DEBUG_TLB
printk("[tlbmm<%lu>]", (unsigned long)cpu_context(cpu, mm));
#endif
- local_irq_save(flags);
- get_new_mmu_context(mm, cpu);
- if (mm == current->active_mm)
- write_c0_entryhi(cpu_context(cpu, mm) & ASID_MASK);
- local_irq_restore(flags);
+ drop_mmu_context(mm, cpu);
}
}
@@ -120,9 +114,7 @@
}
write_c0_entryhi(oldpid);
} else {
- get_new_mmu_context(mm, smp_processor_id());
- if (mm == current->active_mm)
- write_c0_entryhi(cpu_context(cpu, mm) & ASID_MASK);
+ drop_mmu_context(mm, cpu);
}
local_irq_restore(flags);
}
diff -Nru linux/arch/mips64/mm/tlb-sb1.c.orig linux/arch/mips64/mm/tlb-sb1.c
--- linux/arch/mips64/mm/tlb-sb1.c.orig Wed Dec 11 17:04:19 2002
+++ linux/arch/mips64/mm/tlb-sb1.c Tue Feb 4 15:07:42 2003
@@ -180,9 +180,7 @@
}
write_c0_entryhi(oldpid);
} else {
- get_new_mmu_context(mm, cpu);
- if (mm == current->active_mm)
- write_c0_entryhi(cpu_context(cpu, mm) & 0xff);
+ drop_mmu_context(mm, cpu);
}
}
local_irq_restore(flags);
@@ -268,17 +266,10 @@
these entries, we just bump the asid. */
void local_flush_tlb_mm(struct mm_struct *mm)
{
- unsigned long flags;
- int cpu;
- local_irq_save(flags);
- cpu = smp_processor_id();
+ int cpu = smp_processor_id();
if (cpu_context(cpu, mm) != 0) {
- get_new_mmu_context(mm, smp_processor_id());
- if (mm == current->active_mm) {
- write_c0_entryhi(cpu_context(cpu, mm) & 0xff);
- }
+ drop_mmu_context(mm, cpu);
}
- local_irq_restore(flags);
}
/* Stolen from mips32 routines */
diff -Nru linux/arch/mips64/mm/tlb-r4k.c.orig linux/arch/mips64/mm/tlb-r4k.c
--- linux/arch/mips64/mm/tlb-r4k.c.orig Mon Jan 27 18:03:22 2003
+++ linux/arch/mips64/mm/tlb-r4k.c Tue Feb 4 15:08:21 2003
@@ -80,16 +80,10 @@
int cpu = smp_processor_id();
if (cpu_context(cpu, mm) != 0) {
- unsigned long flags;
-
#ifdef DEBUG_TLB
printk("[tlbmm<%d>]", cpu_context(cpu, mm));
#endif
- local_irq_save(flags);
- get_new_mmu_context(mm, cpu);
- if (mm == current->active_mm)
- write_c0_entryhi(cpu_asid(cpu, mm));
- local_irq_restore(flags);
+ drop_mmu_context(mm,cpu);
}
}
@@ -138,9 +132,7 @@
}
write_c0_entryhi(oldpid);
} else {
- get_new_mmu_context(mm, cpu);
- if (mm == current->active_mm)
- write_c0_entryhi(cpu_asid(cpu, mm));
+ drop_mmu_context(mm, cpu);
}
local_irq_restore(flags);
}
diff -Nru linux/arch/mips64/mm/tlb-andes.c.orig linux/arch/mips64/mm/tlb-andes.c
--- linux/arch/mips64/mm/tlb-andes.c.orig Tue Feb 4 13:14:43 2003
+++ linux/arch/mips64/mm/tlb-andes.c Tue Feb 4 14:53:28 2003
@@ -53,18 +53,12 @@
void local_flush_tlb_mm(struct mm_struct *mm)
{
- if (cpu_context(smp_processor_id(), mm) != 0) {
- unsigned long flags;
-
+ int cpu = smp_processor_id();
+ if (cpu_context(cpu, mm) != 0) {
#ifdef DEBUG_TLB
printk("[tlbmm<%d>]", mm->context);
#endif
- local_irq_save(flags);
- get_new_mmu_context(mm, smp_processor_id());
- if (mm == current->active_mm)
- write_c0_entryhi(cpu_context(smp_processor_id(), mm)
- & ASID_MASK);
- local_irq_restore(flags);
+ drop_mmu_context(mm,cpu);
}
}
@@ -108,10 +102,7 @@
}
write_c0_entryhi(oldpid);
} else {
- get_new_mmu_context(mm, smp_processor_id());
- if (mm == current->active_mm)
- write_c0_entryhi(cpu_context(smp_processor_id(), mm)
- & ASID_MASK);
+ drop_mmu_context(mm, cpu);
}
local_irq_restore(flags);
}
diff -Nru linux/include/asm-mips/mmu_context.h.orig linux/include/asm-mips/mmu_context.h
--- linux/include/asm-mips/mmu_context.h.orig Mon Jan 27 18:03:23 2003
+++ linux/include/asm-mips/mmu_context.h Tue Feb 4 14:53:28 2003
@@ -92,12 +92,25 @@
static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
struct task_struct *tsk, unsigned cpu)
{
+ unsigned long flags;
+
+ local_irq_save(flags);
+
/* Check if our ASID is of an older version and thus invalid */
if ((cpu_context(cpu, next) ^ asid_cache(cpu)) & ASID_VERSION_MASK)
get_new_mmu_context(next, cpu);
write_c0_entryhi(cpu_context(cpu, next));
TLBMISS_HANDLER_SETUP_PGD(next->pgd);
+
+ /*
+ * Mark current->active_mm as not "active" anymore.
+ * We don't want to mislead possible IPI tlb flush routines.
+ */
+ clear_bit(cpu, &prev->cpu_vm_mask);
+ set_bit(cpu, &next->cpu_vm_mask);
+
+ local_irq_restore(flags);
}
/*
@@ -115,11 +128,39 @@
static inline void
activate_mm(struct mm_struct *prev, struct mm_struct *next)
{
+ unsigned long flags;
+
+ local_irq_save(flags);
+
/* Unconditionally get a new ASID. */
get_new_mmu_context(next, smp_processor_id());
write_c0_entryhi(cpu_context(smp_processor_id(), next));
TLBMISS_HANDLER_SETUP_PGD(next->pgd);
+
+ local_irq_restore(flags);
+}
+
+/*
+ * If mm is currently active_mm, we can't really drop it. Instead,
+ * we will get a new one for it.
+ */
+static inline void
+drop_mmu_context(struct mm_struct *mm, unsigned cpu)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ if (test_bit(cpu, &mm->cpu_vm_mask)) {
+ get_new_mmu_context(mm, cpu);
+ set_entryhi(CPU_CONTEXT(cpu, mm) & 0xff);
+ } else {
+ /* will get a new context next time */
+ CPU_CONTEXT(cpu, mm) = 0;
+ }
+
+ local_irq_restore(flags);
}
#endif /* _ASM_MMU_CONTEXT_H */
diff -Nru linux/include/asm-mips64/mmu_context.h.orig linux/include/asm-mips64/mmu_context.h
--- linux/include/asm-mips64/mmu_context.h.orig Mon Jan 27 18:03:23 2003
+++ linux/include/asm-mips64/mmu_context.h Tue Feb 4 14:53:28 2003
@@ -83,12 +83,25 @@
static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
struct task_struct *tsk, unsigned cpu)
{
+ unsigned long flags;
+
+ local_irq_save(flags);
+
/* Check if our ASID is of an older version and thus invalid */
if ((cpu_context(cpu, next) ^ asid_cache(cpu)) & ASID_VERSION_MASK)
get_new_mmu_context(next, cpu);
write_c0_entryhi(cpu_context(cpu, next));
TLBMISS_HANDLER_SETUP_PGD(next->pgd);
+
+ /*
+ * Mark current->active_mm as not "active" anymore.
+ * We don't want to mislead possible IPI tlb flush routines.
+ */
+ clear_bit(cpu, &prev->cpu_vm_mask);
+ set_bit(cpu, &next->cpu_vm_mask);
+
+ local_irq_restore(flags);
}
/*
@@ -106,11 +119,39 @@
static inline void
activate_mm(struct mm_struct *prev, struct mm_struct *next)
{
+ unsigned long flags;
+
+ local_irq_save(flags);
+
/* Unconditionally get a new ASID. */
get_new_mmu_context(next, smp_processor_id());
write_c0_entryhi(cpu_context(smp_processor_id(), next));
TLBMISS_HANDLER_SETUP_PGD(next->pgd);
+
+ local_irq_restore(flags);
+}
+
+/*
+ * If mm is currently active_mm, we can't really drop it. Instead,
+ * we will get a new one for it.
+ */
+static inline void
+drop_mmu_context(struct mm_struct *mm, unsigned cpu)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ if (test_bit(cpu, &mm->cpu_vm_mask)) {
+ get_new_mmu_context(mm, cpu);
+ set_entryhi(CPU_CONTEXT(cpu, mm) & 0xff);
+ } else {
+ /* will get a new context next time */
+ CPU_CONTEXT(cpu, mm) = 0;
+ }
+
+ local_irq_restore(flags);
}
#endif /* _ASM_MMU_CONTEXT_H */
next prev parent reply other threads:[~2003-02-05 0:03 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2003-01-21 22:37 [RFC & PATCH] fixing tlb flush race problem on smp Jun Sun
2003-01-22 7:43 ` Juan Quintela
2003-01-28 1:03 ` Jun Sun
2003-01-29 8:06 ` Ralf Baechle
2003-02-05 0:02 ` Jun Sun [this message]
2003-02-05 0:02 ` Jun Sun
2003-02-14 4:48 ` Atsushi Nemoto
2003-02-14 11:06 ` Maciej W. Rozycki
2003-01-29 7:28 ` Ralf Baechle
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20030204160250.F5149@mvista.com \
--to=jsun@mvista.com \
--cc=linux-mips@linux-mips.org \
--cc=quintela@mandrakesoft.com \
--cc=ralf@linux-mips.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox