lkml.org 
[lkml]   [1998]   [Oct]   [14]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
/
Date
From
Subjectget_mmu_context()
Ok, here is a draft version of an agressively optimized version of
get_mmu_context(). I just didn't like the idea of referencing
global variables in get_mmu_context() if avoidable. The code below
will work on both R3000 and R4000 with no performance penalty for
being generic. The trick is to patch the operands of two machine
instructions at runtime, shoot me.

The code below should be integrated into <asm/mmu_context.h>. The
CPU specific code in arch/mips/mm/... will then just have to include
that header file and call r3000_asid_setup rsp. r4xx0_asid_setup.

Have fun,

Ralf

#define ASID_VERSION_SHIFT 16
#define ASID_VERSION_MASK ((~0UL) << ASID_VERSION_SHIFT)
#define ASID_FIRST_VERSION (1UL << ASID_VERSION_SHIFT)

unsigned long asid_cache = ASID_FIRST_VERSION;

/* The next two macros know that they will only be assembled once
per kernel. */
#define ASID_VERSION_INC \
({ unsigned long __asid_inc; \
__asm__(".globl\tasid_inc\n" \
"asid_inc:\n\t" \
"li\t%0,0\t\t\t#patched\n\t" \
:"=r" (__asid_inc)); \
__asid_inc; })

#define ASID_OVERFLOW(asid) \
({ unsigned long __res; \
__asm__(".global\tasid_overflow\n" \
"asid_overflow:\n\t" \
"sltu\t%0,%1,0\t\t\t#patched\n\t" \
:"=r" (__res) \
:"r" (asid)); \
__res; })

extern inline void get_new_mmu_context(struct mm_struct *mm, unsigned long asid)
{
/* check if it's legal.. */
if (ASID_OVERFLOW(asid & ~ASID_VERSION_MASK)) {
/* start a new version, invalidate all old asid's */
flush_tlb_all();
asid = (asid & ASID_VERSION_MASK) + ASID_FIRST_VERSION;
if (!asid)
asid = ASID_FIRST_VERSION;
}
asid_cache = asid + ASID_VERSION_INC;
mm->context = asid; /* full version + asid */
}

extern void get_mmu_context(struct task_struct *p)
{
struct mm_struct *mm = p->mm;

if (mm) {
unsigned long asid = asid_cache;
/* Check if our ASID is of an older version and thus invalid */
if ((mm->context ^ asid) & ASID_VERSION_MASK)
get_new_mmu_context(mm, asid);
}
}

extern inline void __asid_setup(unsigned long asid_inc, unsigned long asid_cmp)
{
extern u32 asid_inc;
extern u32 asid_overflow;

asid_inc = (asid_inc & 0xffff0000) | asid_inc;
flush_icache_range(&asid_inc, 4);
asid_overflow = (asid_overflow & 0xffff0000) | asid_cmp;
flush_icache_range(&asid_overflow, 4);
}

extern inline void r3000_asid_setup(void)
{
__asid_setup(0x40, 0xfc1);
}

extern inline void r4xx0_asid_setup(void)
{
__asid_setup(1, 0x100);
}

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/

\
 
 \ /
  Last update: 2005-03-22 13:45    [W:1.020 / U:0.112 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site