diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2001-01-10 17:17:53 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2001-01-10 17:17:53 +0000 |
commit | b2ad5f821b1381492d792ca10b1eb7a107b48f14 (patch) | |
tree | 954a648692e7da983db1d2470953705f6a729264 /include/asm-alpha | |
parent | c9c06167e7933d93a6e396174c68abf242294abb (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.h | 7 | ||||
-rw-r--r-- | include/asm-alpha/mmu_context.h | 53 | ||||
-rw-r--r-- | include/asm-alpha/pgalloc.h | 69 | ||||
-rw-r--r-- | include/asm-alpha/processor.h | 1 | ||||
-rw-r--r-- | include/asm-alpha/smp.h | 2 | ||||
-rw-r--r-- | include/asm-alpha/system.h | 1 |
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(¤t->thread); \ (last) = alpha_switch_to(pcbb, (prev)); \ + check_mmu_context(); \ } while (0) extern struct task_struct* alpha_switch_to(unsigned long, struct task_struct*); |