| 1 |
199 |
simons |
#ifndef __ALPHA_MMU_CONTEXT_H
|
| 2 |
|
|
#define __ALPHA_MMU_CONTEXT_H
|
| 3 |
|
|
|
| 4 |
|
|
/*
|
| 5 |
|
|
* get a new mmu context..
|
| 6 |
|
|
*
|
| 7 |
|
|
* Copyright (C) 1996, Linus Torvalds
|
| 8 |
|
|
*/
|
| 9 |
|
|
|
| 10 |
|
|
#include <linux/config.h>
|
| 11 |
|
|
#include <asm/system.h>
|
| 12 |
|
|
|
| 13 |
|
|
/*
|
| 14 |
|
|
* The maximum ASN's the processor supports. On the EV4 this is 63
|
| 15 |
|
|
* but the PAL-code doesn't actually use this information. On the
|
| 16 |
|
|
* EV5 this is 127.
|
| 17 |
|
|
*
|
| 18 |
|
|
* On the EV4, the ASNs are more-or-less useless anyway, as they are
|
| 19 |
|
|
* only used as a icache tag, not for TB entries. On the EV5 ASN's
|
| 20 |
|
|
* also validate the TB entries, and thus make a lot more sense.
|
| 21 |
|
|
*
|
| 22 |
|
|
* The EV4 ASN's don't even match the architecture manual, ugh. And
|
| 23 |
|
|
* I quote: "If a processor implements address space numbers (ASNs),
|
| 24 |
|
|
* and the old PTE has the Address Space Match (ASM) bit clear (ASNs
|
| 25 |
|
|
* in use) and the Valid bit set, then entries can also effectively be
|
| 26 |
|
|
* made coherent by assigning a new, unused ASN to the currently
|
| 27 |
|
|
* running process and not reusing the previous ASN before calling the
|
| 28 |
|
|
* appropriate PALcode routine to invalidate the translation buffer
|
| 29 |
|
|
* (TB)".
|
| 30 |
|
|
*
|
| 31 |
|
|
* In short, the EV4 has a "kind of" ASN capability, but it doesn't actually
|
| 32 |
|
|
* work correctly and can thus not be used (explaining the lack of PAL-code
|
| 33 |
|
|
* support).
|
| 34 |
|
|
*/
|
| 35 |
|
|
#ifdef CONFIG_ALPHA_EV5
|
| 36 |
|
|
#define MAX_ASN 127
|
| 37 |
|
|
#else
|
| 38 |
|
|
#define MAX_ASN 63
|
| 39 |
|
|
#define BROKEN_ASN 1
|
| 40 |
|
|
#endif
|
| 41 |
|
|
|
| 42 |
|
|
extern unsigned long asn_cache;
|
| 43 |
|
|
|
| 44 |
|
|
#define ASN_VERSION_SHIFT 16
|
| 45 |
|
|
#define ASN_VERSION_MASK ((~0UL) << ASN_VERSION_SHIFT)
|
| 46 |
|
|
#define ASN_FIRST_VERSION (1UL << ASN_VERSION_SHIFT)
|
| 47 |
|
|
|
| 48 |
|
|
extern inline void get_new_mmu_context(struct task_struct *p,
|
| 49 |
|
|
struct mm_struct *mm,
|
| 50 |
|
|
unsigned long asn)
|
| 51 |
|
|
{
|
| 52 |
|
|
/* check if it's legal.. */
|
| 53 |
|
|
if ((asn & ~ASN_VERSION_MASK) > MAX_ASN) {
|
| 54 |
|
|
/* start a new version, invalidate all old asn's */
|
| 55 |
|
|
tbiap(); imb();
|
| 56 |
|
|
asn = (asn & ASN_VERSION_MASK) + ASN_FIRST_VERSION;
|
| 57 |
|
|
if (!asn)
|
| 58 |
|
|
asn = ASN_FIRST_VERSION;
|
| 59 |
|
|
}
|
| 60 |
|
|
asn_cache = asn + 1;
|
| 61 |
|
|
mm->context = asn; /* full version + asn */
|
| 62 |
|
|
p->tss.asn = asn & ~ASN_VERSION_MASK; /* just asn */
|
| 63 |
|
|
}
|
| 64 |
|
|
|
| 65 |
|
|
/*
|
| 66 |
|
|
* NOTE! The way this is set up, the high bits of the "asn_cache" (and
|
| 67 |
|
|
* the "mm->context") are the ASN _version_ code. A version of 0 is
|
| 68 |
|
|
* always considered invalid, so to invalidate another process you only
|
| 69 |
|
|
* need to do "p->mm->context = 0".
|
| 70 |
|
|
*
|
| 71 |
|
|
* If we need more ASN's than the processor has, we invalidate the old
|
| 72 |
|
|
* user TLB's (tbiap()) and start a new ASN version. That will automatically
|
| 73 |
|
|
* force a new asn for any other processes the next time they want to
|
| 74 |
|
|
* run.
|
| 75 |
|
|
*/
|
| 76 |
|
|
extern inline void get_mmu_context(struct task_struct *p)
|
| 77 |
|
|
{
|
| 78 |
|
|
#ifndef BROKEN_ASN
|
| 79 |
|
|
struct mm_struct * mm = p->mm;
|
| 80 |
|
|
|
| 81 |
|
|
if (mm) {
|
| 82 |
|
|
unsigned long asn = asn_cache;
|
| 83 |
|
|
/* Check if our ASN is of an older version and thus invalid */
|
| 84 |
|
|
if ((mm->context ^ asn) & ASN_VERSION_MASK)
|
| 85 |
|
|
get_new_mmu_context(p, mm, asn);
|
| 86 |
|
|
}
|
| 87 |
|
|
#endif
|
| 88 |
|
|
}
|
| 89 |
|
|
|
| 90 |
|
|
#endif
|