linux/arch/mips/include/asm/mmu_context.h
<<
>>
Prefs
   1/*
   2 * Switch a MMU context.
   3 *
   4 * This file is subject to the terms and conditions of the GNU General Public
   5 * License.  See the file "COPYING" in the main directory of this archive
   6 * for more details.
   7 *
   8 * Copyright (C) 1996, 1997, 1998, 1999 by Ralf Baechle
   9 * Copyright (C) 1999 Silicon Graphics, Inc.
  10 */
  11#ifndef _ASM_MMU_CONTEXT_H
  12#define _ASM_MMU_CONTEXT_H
  13
  14#include <linux/errno.h>
  15#include <linux/sched.h>
  16#include <linux/slab.h>
  17#include <asm/cacheflush.h>
  18#include <asm/tlbflush.h>
  19#ifdef CONFIG_MIPS_MT_SMTC
  20#include <asm/mipsmtregs.h>
  21#include <asm/smtc.h>
  22#endif /* SMTC */
  23#include <asm-generic/mm_hooks.h>
  24
  25/*
  26 * For the fast tlb miss handlers, we keep a per cpu array of pointers
  27 * to the current pgd for each processor. Also, the proc. id is stuffed
  28 * into the context register.
  29 */
  30extern unsigned long pgd_current[];
  31
  32#define TLBMISS_HANDLER_SETUP_PGD(pgd) \
  33        pgd_current[smp_processor_id()] = (unsigned long)(pgd)
  34
  35#ifdef CONFIG_32BIT
  36#define TLBMISS_HANDLER_SETUP()                                         \
  37        write_c0_context((unsigned long) smp_processor_id() << 25);     \
  38        TLBMISS_HANDLER_SETUP_PGD(swapper_pg_dir)
  39#endif
  40#ifdef CONFIG_64BIT
  41#define TLBMISS_HANDLER_SETUP()                                         \
  42        write_c0_context((unsigned long) smp_processor_id() << 26);     \
  43        TLBMISS_HANDLER_SETUP_PGD(swapper_pg_dir)
  44#endif
  45
  46#if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX)
  47
  48#define ASID_INC        0x40
  49#define ASID_MASK       0xfc0
  50
  51#elif defined(CONFIG_CPU_R8000)
  52
  53#define ASID_INC        0x10
  54#define ASID_MASK       0xff0
  55
  56#elif defined(CONFIG_CPU_RM9000)
  57
  58#define ASID_INC        0x1
  59#define ASID_MASK       0xfff
  60
  61/* SMTC/34K debug hack - but maybe we'll keep it */
  62#elif defined(CONFIG_MIPS_MT_SMTC)
  63
  64#define ASID_INC        0x1
  65extern unsigned long smtc_asid_mask;
  66#define ASID_MASK       (smtc_asid_mask)
  67#define HW_ASID_MASK    0xff
  68/* End SMTC/34K debug hack */
  69#else /* FIXME: not correct for R6000 */
  70
  71#define ASID_INC        0x1
  72#define ASID_MASK       0xff
  73
  74#endif
  75
  76#define cpu_context(cpu, mm)    ((mm)->context[cpu])
  77#define cpu_asid(cpu, mm)       (cpu_context((cpu), (mm)) & ASID_MASK)
  78#define asid_cache(cpu)         (cpu_data[cpu].asid_cache)
  79
  80static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
  81{
  82}
  83
  84/*
  85 *  All unused by hardware upper bits will be considered
  86 *  as a software asid extension.
  87 */
  88#define ASID_VERSION_MASK  ((unsigned long)~(ASID_MASK|(ASID_MASK-1)))
  89#define ASID_FIRST_VERSION ((unsigned long)(~ASID_VERSION_MASK) + 1)
  90
  91#ifndef CONFIG_MIPS_MT_SMTC
  92/* Normal, classic MIPS get_new_mmu_context */
  93static inline void
  94get_new_mmu_context(struct mm_struct *mm, unsigned long cpu)
  95{
  96        unsigned long asid = asid_cache(cpu);
  97
  98        if (! ((asid += ASID_INC) & ASID_MASK) ) {
  99                if (cpu_has_vtag_icache)
 100                        flush_icache_all();
 101                local_flush_tlb_all();  /* start new asid cycle */
 102                if (!asid)              /* fix version if needed */
 103                        asid = ASID_FIRST_VERSION;
 104        }
 105        cpu_context(cpu, mm) = asid_cache(cpu) = asid;
 106}
 107
 108#else /* CONFIG_MIPS_MT_SMTC */
 109
 110#define get_new_mmu_context(mm, cpu) smtc_get_new_mmu_context((mm), (cpu))
 111
 112#endif /* CONFIG_MIPS_MT_SMTC */
 113
 114/*
 115 * Initialize the context related info for a new mm_struct
 116 * instance.
 117 */
 118static inline int
 119init_new_context(struct task_struct *tsk, struct mm_struct *mm)
 120{
 121        int i;
 122
 123        for_each_online_cpu(i)
 124                cpu_context(i, mm) = 0;
 125
 126        return 0;
 127}
 128
 129static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
 130                             struct task_struct *tsk)
 131{
 132        unsigned int cpu = smp_processor_id();
 133        unsigned long flags;
 134#ifdef CONFIG_MIPS_MT_SMTC
 135        unsigned long oldasid;
 136        unsigned long mtflags;
 137        int mytlb = (smtc_status & SMTC_TLB_SHARED) ? 0 : cpu_data[cpu].vpe_id;
 138        local_irq_save(flags);
 139        mtflags = dvpe();
 140#else /* Not SMTC */
 141        local_irq_save(flags);
 142#endif /* CONFIG_MIPS_MT_SMTC */
 143
 144        /* Check if our ASID is of an older version and thus invalid */
 145        if ((cpu_context(cpu, next) ^ asid_cache(cpu)) & ASID_VERSION_MASK)
 146                get_new_mmu_context(next, cpu);
 147#ifdef CONFIG_MIPS_MT_SMTC
 148        /*
 149         * If the EntryHi ASID being replaced happens to be
 150         * the value flagged at ASID recycling time as having
 151         * an extended life, clear the bit showing it being
 152         * in use by this "CPU", and if that's the last bit,
 153         * free up the ASID value for use and flush any old
 154         * instances of it from the TLB.
 155         */
 156        oldasid = (read_c0_entryhi() & ASID_MASK);
 157        if(smtc_live_asid[mytlb][oldasid]) {
 158                smtc_live_asid[mytlb][oldasid] &= ~(0x1 << cpu);
 159                if(smtc_live_asid[mytlb][oldasid] == 0)
 160                        smtc_flush_tlb_asid(oldasid);
 161        }
 162        /*
 163         * Tread softly on EntryHi, and so long as we support
 164         * having ASID_MASK smaller than the hardware maximum,
 165         * make sure no "soft" bits become "hard"...
 166         */
 167        write_c0_entryhi((read_c0_entryhi() & ~HW_ASID_MASK)
 168                        | (cpu_context(cpu, next) & ASID_MASK));
 169        ehb(); /* Make sure it propagates to TCStatus */
 170        evpe(mtflags);
 171#else
 172        write_c0_entryhi(cpu_context(cpu, next));
 173#endif /* CONFIG_MIPS_MT_SMTC */
 174        TLBMISS_HANDLER_SETUP_PGD(next->pgd);
 175
 176        /*
 177         * Mark current->active_mm as not "active" anymore.
 178         * We don't want to mislead possible IPI tlb flush routines.
 179         */
 180        cpu_clear(cpu, prev->cpu_vm_mask);
 181        cpu_set(cpu, next->cpu_vm_mask);
 182
 183        local_irq_restore(flags);
 184}
 185
 186/*
 187 * Destroy context related info for an mm_struct that is about
 188 * to be put to rest.
 189 */
 190static inline void destroy_context(struct mm_struct *mm)
 191{
 192}
 193
 194#define deactivate_mm(tsk, mm)  do { } while (0)
 195
 196/*
 197 * After we have set current->mm to a new value, this activates
 198 * the context for the new mm so we see the new mappings.
 199 */
 200static inline void
 201activate_mm(struct mm_struct *prev, struct mm_struct *next)
 202{
 203        unsigned long flags;
 204        unsigned int cpu = smp_processor_id();
 205
 206#ifdef CONFIG_MIPS_MT_SMTC
 207        unsigned long oldasid;
 208        unsigned long mtflags;
 209        int mytlb = (smtc_status & SMTC_TLB_SHARED) ? 0 : cpu_data[cpu].vpe_id;
 210#endif /* CONFIG_MIPS_MT_SMTC */
 211
 212        local_irq_save(flags);
 213
 214        /* Unconditionally get a new ASID.  */
 215        get_new_mmu_context(next, cpu);
 216
 217#ifdef CONFIG_MIPS_MT_SMTC
 218        /* See comments for similar code above */
 219        mtflags = dvpe();
 220        oldasid = read_c0_entryhi() & ASID_MASK;
 221        if(smtc_live_asid[mytlb][oldasid]) {
 222                smtc_live_asid[mytlb][oldasid] &= ~(0x1 << cpu);
 223                if(smtc_live_asid[mytlb][oldasid] == 0)
 224                         smtc_flush_tlb_asid(oldasid);
 225        }
 226        /* See comments for similar code above */
 227        write_c0_entryhi((read_c0_entryhi() & ~HW_ASID_MASK) |
 228                         (cpu_context(cpu, next) & ASID_MASK));
 229        ehb(); /* Make sure it propagates to TCStatus */
 230        evpe(mtflags);
 231#else
 232        write_c0_entryhi(cpu_context(cpu, next));
 233#endif /* CONFIG_MIPS_MT_SMTC */
 234        TLBMISS_HANDLER_SETUP_PGD(next->pgd);
 235
 236        /* mark mmu ownership change */
 237        cpu_clear(cpu, prev->cpu_vm_mask);
 238        cpu_set(cpu, next->cpu_vm_mask);
 239
 240        local_irq_restore(flags);
 241}
 242
 243/*
 244 * If mm is currently active_mm, we can't really drop it.  Instead,
 245 * we will get a new one for it.
 246 */
 247static inline void
 248drop_mmu_context(struct mm_struct *mm, unsigned cpu)
 249{
 250        unsigned long flags;
 251#ifdef CONFIG_MIPS_MT_SMTC
 252        unsigned long oldasid;
 253        /* Can't use spinlock because called from TLB flush within DVPE */
 254        unsigned int prevvpe;
 255        int mytlb = (smtc_status & SMTC_TLB_SHARED) ? 0 : cpu_data[cpu].vpe_id;
 256#endif /* CONFIG_MIPS_MT_SMTC */
 257
 258        local_irq_save(flags);
 259
 260        if (cpu_isset(cpu, mm->cpu_vm_mask))  {
 261                get_new_mmu_context(mm, cpu);
 262#ifdef CONFIG_MIPS_MT_SMTC
 263                /* See comments for similar code above */
 264                prevvpe = dvpe();
 265                oldasid = (read_c0_entryhi() & ASID_MASK);
 266                if (smtc_live_asid[mytlb][oldasid]) {
 267                        smtc_live_asid[mytlb][oldasid] &= ~(0x1 << cpu);
 268                        if(smtc_live_asid[mytlb][oldasid] == 0)
 269                                smtc_flush_tlb_asid(oldasid);
 270                }
 271                /* See comments for similar code above */
 272                write_c0_entryhi((read_c0_entryhi() & ~HW_ASID_MASK)
 273                                | cpu_asid(cpu, mm));
 274                ehb(); /* Make sure it propagates to TCStatus */
 275                evpe(prevvpe);
 276#else /* not CONFIG_MIPS_MT_SMTC */
 277                write_c0_entryhi(cpu_asid(cpu, mm));
 278#endif /* CONFIG_MIPS_MT_SMTC */
 279        } else {
 280                /* will get a new context next time */
 281#ifndef CONFIG_MIPS_MT_SMTC
 282                cpu_context(cpu, mm) = 0;
 283#else /* SMTC */
 284                int i;
 285
 286                /* SMTC shares the TLB (and ASIDs) across VPEs */
 287                for_each_online_cpu(i) {
 288                    if((smtc_status & SMTC_TLB_SHARED)
 289                    || (cpu_data[i].vpe_id == cpu_data[cpu].vpe_id))
 290                        cpu_context(i, mm) = 0;
 291                }
 292#endif /* CONFIG_MIPS_MT_SMTC */
 293        }
 294        local_irq_restore(flags);
 295}
 296
 297#endif /* _ASM_MMU_CONTEXT_H */
 298
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.