summaryrefslogtreecommitdiffstats
path: root/include/asm-alpha
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2001-01-10 17:17:53 +0000
committerRalf Baechle <ralf@linux-mips.org>2001-01-10 17:17:53 +0000
commitb2ad5f821b1381492d792ca10b1eb7a107b48f14 (patch)
tree954a648692e7da983db1d2470953705f6a729264 /include/asm-alpha
parentc9c06167e7933d93a6e396174c68abf242294abb (diff)
Merge with Linux 2.4.0-prerelease. Big Makefile rewrite, test your
Makefiles.
Diffstat (limited to 'include/asm-alpha')
-rw-r--r--include/asm-alpha/mmu.h7
-rw-r--r--include/asm-alpha/mmu_context.h53
-rw-r--r--include/asm-alpha/pgalloc.h69
-rw-r--r--include/asm-alpha/processor.h1
-rw-r--r--include/asm-alpha/smp.h2
-rw-r--r--include/asm-alpha/system.h1
6 files changed, 84 insertions, 49 deletions
diff --git a/include/asm-alpha/mmu.h b/include/asm-alpha/mmu.h
new file mode 100644
index 000000000..3dc127779
--- /dev/null
+++ b/include/asm-alpha/mmu.h
@@ -0,0 +1,7 @@
+#ifndef __ALPHA_MMU_H
+#define __ALPHA_MMU_H
+
+/* The alpha MMU context is one "unsigned long" bitmap per CPU */
+typedef unsigned long mm_context_t[NR_CPUS];
+
+#endif
diff --git a/include/asm-alpha/mmu_context.h b/include/asm-alpha/mmu_context.h
index 219b8bd4e..492d29b7c 100644
--- a/include/asm-alpha/mmu_context.h
+++ b/include/asm-alpha/mmu_context.h
@@ -11,7 +11,6 @@
#include <asm/system.h>
#include <asm/machvec.h>
-
/*
* Force a context reload. This is needed when we change the page
* table pointer or when we update the ASN of the current process.
@@ -93,12 +92,7 @@ extern unsigned long last_asn;
#endif /* CONFIG_SMP */
#define WIDTH_HARDWARE_ASN 8
-#ifdef CONFIG_SMP
-#define WIDTH_THIS_PROCESSOR 5
-#else
-#define WIDTH_THIS_PROCESSOR 0
-#endif
-#define ASN_FIRST_VERSION (1UL << (WIDTH_THIS_PROCESSOR + WIDTH_HARDWARE_ASN))
+#define ASN_FIRST_VERSION (1UL << WIDTH_HARDWARE_ASN)
#define HARDWARE_ASN_MASK ((1UL << WIDTH_HARDWARE_ASN) - 1)
/*
@@ -137,19 +131,24 @@ __EXTERN_INLINE void
ev5_switch_mm(struct mm_struct *prev_mm, struct mm_struct *next_mm,
struct task_struct *next, long cpu)
{
- /* Check if our ASN is of an older version, or on a different CPU,
- and thus invalid. */
- /* ??? If we have two threads on different cpus, we'll continually
- fight over the context. Find a way to record a per-mm, per-cpu
- value for the asn. */
+ /* Check if our ASN is of an older version, and thus invalid. */
+ unsigned long asn;
+ unsigned long mmc;
- unsigned long asn = cpu_last_asn(cpu);
- unsigned long mmc = next_mm->context;
-
+#ifdef CONFIG_SMP
+ cpu_data[cpu].asn_lock = 1;
+ barrier();
+#endif
+ asn = cpu_last_asn(cpu);
+ mmc = next_mm->context[cpu];
if ((mmc ^ asn) & ~HARDWARE_ASN_MASK) {
mmc = __get_new_mm_context(next_mm, cpu);
- next_mm->context = mmc;
+ next_mm->context[cpu] = mmc;
}
+#ifdef CONFIG_SMP
+ else
+ cpu_data[cpu].need_new_asn = 1;
+#endif
/* Always update the PCB ASN. Another thread may have allocated
a new mm->context (via flush_tlb_mm) without the ASN serial
@@ -179,6 +178,23 @@ ev4_switch_mm(struct mm_struct *prev_mm, struct mm_struct *next_mm,
extern void __load_new_mm_context(struct mm_struct *);
+#ifdef CONFIG_SMP
+#define check_mmu_context() \
+do { \
+ int cpu = smp_processor_id(); \
+ cpu_data[cpu].asn_lock = 0; \
+ barrier(); \
+ if (cpu_data[cpu].need_new_asn) { \
+ struct mm_struct * mm = current->active_mm; \
+ cpu_data[cpu].need_new_asn = 0; \
+ if (!mm->context[cpu]) \
+ __load_new_mm_context(mm); \
+ } \
+} while(0)
+#else
+#define check_mmu_context() do { } while(0)
+#endif
+
__EXTERN_INLINE void
ev5_activate_mm(struct mm_struct *prev_mm, struct mm_struct *next_mm)
{
@@ -208,7 +224,10 @@ ev4_activate_mm(struct mm_struct *prev_mm, struct mm_struct *next_mm)
extern inline int
init_new_context(struct task_struct *tsk, struct mm_struct *mm)
{
- mm->context = 0;
+ int i;
+
+ for (i = 0; i < smp_num_cpus; i++)
+ mm->context[cpu_logical_map(i)] = 0;
tsk->thread.ptbr = ((unsigned long)mm->pgd - IDENT_ADDR) >> PAGE_SHIFT;
return 0;
}
diff --git a/include/asm-alpha/pgalloc.h b/include/asm-alpha/pgalloc.h
index dd09a2eec..7e377bdfd 100644
--- a/include/asm-alpha/pgalloc.h
+++ b/include/asm-alpha/pgalloc.h
@@ -38,29 +38,6 @@ extern void __load_new_mm_context(struct mm_struct *);
extern void smp_imb(void);
#endif
-/* We need to flush the userspace icache after setting breakpoints in
- ptrace. I don't think it's needed in do_swap_page, or do_no_page,
- but I don't know how to get rid of it either.
-
- Instead of indiscriminately using imb, take advantage of the fact
- that icache entries are tagged with the ASN and load a new mm context. */
-/* ??? Ought to use this in arch/alpha/kernel/signal.c too. */
-
-#ifndef CONFIG_SMP
-static inline void
-flush_icache_page(struct vm_area_struct *vma, struct page *page)
-{
- if (vma->vm_flags & VM_EXEC) {
- struct mm_struct *mm = vma->vm_mm;
- mm->context = 0;
- if (current->active_mm == mm)
- __load_new_mm_context(mm);
- }
-}
-#else
-extern void flush_icache_page(struct vm_area_struct *vma, struct page *page);
-#endif
-
/*
* Use a few helper functions to hide the ugly broken ASN
@@ -83,8 +60,38 @@ ev5_flush_tlb_current(struct mm_struct *mm)
static inline void
flush_tlb_other(struct mm_struct *mm)
{
- mm->context = 0;
+ long * mmc = &mm->context[smp_processor_id()];
+ /*
+ * Check it's not zero first to avoid cacheline ping pong when
+ * possible.
+ */
+ if (*mmc)
+ *mmc = 0;
+}
+
+/* We need to flush the userspace icache after setting breakpoints in
+ ptrace. I don't think it's needed in do_swap_page, or do_no_page,
+ but I don't know how to get rid of it either.
+
+ Instead of indiscriminately using imb, take advantage of the fact
+ that icache entries are tagged with the ASN and load a new mm context. */
+/* ??? Ought to use this in arch/alpha/kernel/signal.c too. */
+
+#ifndef CONFIG_SMP
+static inline void
+flush_icache_page(struct vm_area_struct *vma, struct page *page)
+{
+ if (vma->vm_flags & VM_EXEC) {
+ struct mm_struct *mm = vma->vm_mm;
+ if (current->active_mm == mm)
+ __load_new_mm_context(mm);
+ else
+ mm->context[smp_processor_id()] = 0;
+ }
}
+#else
+extern void flush_icache_page(struct vm_area_struct *vma, struct page *page);
+#endif
/*
* Flush just one page in the current TLB set.
@@ -140,7 +147,7 @@ ev5_flush_tlb_current_page(struct mm_struct * mm,
*/
static inline void flush_tlb(void)
{
- flush_tlb_current(current->mm);
+ flush_tlb_current(current->active_mm);
}
/*
@@ -170,10 +177,10 @@ static inline void flush_tlb_all(void)
*/
static inline void flush_tlb_mm(struct mm_struct *mm)
{
- if (mm != current->mm)
- flush_tlb_other(mm);
- else
+ if (mm == current->active_mm)
flush_tlb_current(mm);
+ else
+ flush_tlb_other(mm);
}
/*
@@ -189,10 +196,10 @@ static inline void flush_tlb_page(struct vm_area_struct *vma,
{
struct mm_struct * mm = vma->vm_mm;
- if (mm != current->mm)
- flush_tlb_other(mm);
- else
+ if (mm == current->active_mm)
flush_tlb_current_page(mm, vma, addr);
+ else
+ flush_tlb_other(mm);
}
/*
diff --git a/include/asm-alpha/processor.h b/include/asm-alpha/processor.h
index 81427025c..49f228f3f 100644
--- a/include/asm-alpha/processor.h
+++ b/include/asm-alpha/processor.h
@@ -124,7 +124,6 @@ extern long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
#define copy_segments(tsk, mm) do { } while (0)
#define release_segments(mm) do { } while (0)
-#define forget_segments() do { } while (0)
unsigned long get_wchan(struct task_struct *p);
diff --git a/include/asm-alpha/smp.h b/include/asm-alpha/smp.h
index 44ec5e8ea..6331af6f2 100644
--- a/include/asm-alpha/smp.h
+++ b/include/asm-alpha/smp.h
@@ -26,6 +26,8 @@ __hard_smp_processor_id(void)
struct cpuinfo_alpha {
unsigned long loops_per_sec;
unsigned long last_asn;
+ int need_new_asn;
+ int asn_lock;
unsigned long *pgd_cache;
unsigned long *pte_cache;
unsigned long pgtable_cache_sz;
diff --git a/include/asm-alpha/system.h b/include/asm-alpha/system.h
index 6d34c5472..3a8c9385d 100644
--- a/include/asm-alpha/system.h
+++ b/include/asm-alpha/system.h
@@ -125,6 +125,7 @@ do { \
current = (next); \
pcbb = virt_to_phys(&current->thread); \
(last) = alpha_switch_to(pcbb, (prev)); \
+ check_mmu_context(); \
} while (0)
extern struct task_struct* alpha_switch_to(unsigned long, struct task_struct*);