diff options
| author | Anton Blanchard <anton@samba.org> | 2004-09-16 21:56:50 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2004-09-16 21:56:50 -0700 |
| commit | ee3ff5760f2011d2f2f2b6f9b39cb0be0d1df422 (patch) | |
| tree | cc4808d3c93a3d7a5d12817195445dcc3cb46d37 | |
| parent | 06a7e66d9b2b0c7306f734266670506fa5448e64 (diff) | |
[PATCH] ppc64: replace mmu_context_queue with idr allocator
Replace the mmu_context_queue structure with the idr allocator. The
mmu_context_queue allocation was quite large (~200kB) so on most machines
we will have a reduction in usage.
We might put a single entry cache on the front of this so we are more
likely to reuse ppc64 MMU hashtable entries that are in the caches.
Signed-off-by: Anton Blanchard <anton@samba.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
| -rw-r--r-- | arch/ppc64/mm/init.c | 67 | ||||
| -rw-r--r-- | include/asm-ppc64/mmu_context.h | 104 |
2 files changed, 59 insertions, 112 deletions
diff --git a/arch/ppc64/mm/init.c b/arch/ppc64/mm/init.c index 081e65a5de5d..026cf352ea71 100644 --- a/arch/ppc64/mm/init.c +++ b/arch/ppc64/mm/init.c @@ -36,6 +36,7 @@ #include <linux/delay.h> #include <linux/bootmem.h> #include <linux/highmem.h> +#include <linux/idr.h> #include <asm/pgalloc.h> #include <asm/page.h> @@ -62,8 +63,6 @@ #include <asm/iommu.h> #include <asm/abs_addr.h> - -struct mmu_context_queue_t mmu_context_queue; int mem_init_done; unsigned long ioremap_bot = IMALLOC_BASE; static unsigned long phbs_io_bot = PHBS_IO_BASE; @@ -477,6 +476,59 @@ void free_initrd_mem(unsigned long start, unsigned long end) } #endif +static spinlock_t mmu_context_lock = SPIN_LOCK_UNLOCKED; +static DEFINE_IDR(mmu_context_idr); + +int init_new_context(struct task_struct *tsk, struct mm_struct *mm) +{ + int index; + int err; + +again: + if (!idr_pre_get(&mmu_context_idr, GFP_KERNEL)) + return -ENOMEM; + + spin_lock(&mmu_context_lock); + err = idr_get_new(&mmu_context_idr, NULL, &index); + spin_unlock(&mmu_context_lock); + + if (err == -EAGAIN) + goto again; + else if (err) + return err; + + if (index > MAX_CONTEXT) { + idr_remove(&mmu_context_idr, index); + return -ENOMEM; + } + + mm->context.id = index; + + return 0; +} + +void destroy_context(struct mm_struct *mm) +{ + spin_lock(&mmu_context_lock); + idr_remove(&mmu_context_idr, mm->context.id); + spin_unlock(&mmu_context_lock); + + mm->context.id = NO_CONTEXT; +} + +static int __init mmu_context_init(void) +{ + int index; + + /* Reserve the first (invalid) context*/ + idr_pre_get(&mmu_context_idr, GFP_KERNEL); + idr_get_new(&mmu_context_idr, NULL, &index); + BUG_ON(0 != index); + + return 0; +} +arch_initcall(mmu_context_init); + /* * Do very early mm setup. */ @@ -486,17 +538,6 @@ void __init mm_init_ppc64(void) ppc64_boot_msg(0x100, "MM Init"); - /* Reserve all contexts < FIRST_USER_CONTEXT for kernel use. - * The range of contexts [FIRST_USER_CONTEXT, NUM_USER_CONTEXT) - * are stored on a stack/queue for easy allocation and deallocation. - */ - mmu_context_queue.lock = SPIN_LOCK_UNLOCKED; - mmu_context_queue.head = 0; - mmu_context_queue.tail = NUM_USER_CONTEXT-1; - mmu_context_queue.size = NUM_USER_CONTEXT; - for (i = 0; i < NUM_USER_CONTEXT; i++) - mmu_context_queue.elements[i] = i + FIRST_USER_CONTEXT; - /* This is the story of the IO hole... please, keep seated, * unfortunately, we are out of oxygen masks at the moment. * So we need some rough way to tell where your big IO hole diff --git a/include/asm-ppc64/mmu_context.h b/include/asm-ppc64/mmu_context.h index d08d9a9e4342..d69033fd0b8a 100644 --- a/include/asm-ppc64/mmu_context.h +++ b/include/asm-ppc64/mmu_context.h @@ -2,11 +2,9 @@ #define __PPC64_MMU_CONTEXT_H #include <linux/config.h> -#include <linux/spinlock.h> #include <linux/kernel.h> #include <linux/mm.h> #include <asm/mmu.h> -#include <asm/ppcdebug.h> #include <asm/cputable.h> /* @@ -33,107 +31,15 @@ static inline int sched_find_first_bit(unsigned long *b) return __ffs(b[2]) + 128; } -#define NO_CONTEXT 0 -#define FIRST_USER_CONTEXT 1 -#define LAST_USER_CONTEXT 0x8000 /* Same as PID_MAX for now... */ -#define NUM_USER_CONTEXT (LAST_USER_CONTEXT-FIRST_USER_CONTEXT) - -/* Choose whether we want to implement our context - * number allocator as a LIFO or FIFO queue. - */ -#if 1 -#define MMU_CONTEXT_LIFO -#else -#define MMU_CONTEXT_FIFO -#endif - -struct mmu_context_queue_t { - spinlock_t lock; - long head; - long tail; - long size; - mm_context_id_t elements[LAST_USER_CONTEXT]; -}; - -extern struct mmu_context_queue_t mmu_context_queue; - -static inline void -enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) -{ -} - -/* - * The context number queue has underflowed. - * Meaning: we tried to push a context number that was freed - * back onto the context queue and the queue was already full. - */ -static inline void -mmu_context_underflow(void) +static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) { - printk(KERN_DEBUG "mmu_context_underflow\n"); - panic("mmu_context_underflow"); } -/* - * Set up the context for a new address space. - */ -static inline int -init_new_context(struct task_struct *tsk, struct mm_struct *mm) -{ - long head; - unsigned long flags; - /* This does the right thing across a fork (I hope) */ - - spin_lock_irqsave(&mmu_context_queue.lock, flags); - - if (mmu_context_queue.size <= 0) { - spin_unlock_irqrestore(&mmu_context_queue.lock, flags); - return -ENOMEM; - } +#define NO_CONTEXT 0 +#define MAX_CONTEXT (0x100000-1) - head = mmu_context_queue.head; - mm->context.id = mmu_context_queue.elements[head]; - - head = (head < LAST_USER_CONTEXT-1) ? head+1 : 0; - mmu_context_queue.head = head; - mmu_context_queue.size--; - - spin_unlock_irqrestore(&mmu_context_queue.lock, flags); - - return 0; -} - -/* - * We're finished using the context for an address space. - */ -static inline void -destroy_context(struct mm_struct *mm) -{ - long index; - unsigned long flags; - - spin_lock_irqsave(&mmu_context_queue.lock, flags); - - if (mmu_context_queue.size >= NUM_USER_CONTEXT) { - spin_unlock_irqrestore(&mmu_context_queue.lock, flags); - mmu_context_underflow(); - } - -#ifdef MMU_CONTEXT_LIFO - index = mmu_context_queue.head; - index = (index > 0) ? index-1 : LAST_USER_CONTEXT-1; - mmu_context_queue.head = index; -#else - index = mmu_context_queue.tail; - index = (index < LAST_USER_CONTEXT-1) ? index+1 : 0; - mmu_context_queue.tail = index; -#endif - - mmu_context_queue.size++; - mmu_context_queue.elements[index] = mm->context.id; - - spin_unlock_irqrestore(&mmu_context_queue.lock, flags); -} +extern int init_new_context(struct task_struct *tsk, struct mm_struct *mm); +extern void destroy_context(struct mm_struct *mm); extern void switch_stab(struct task_struct *tsk, struct mm_struct *mm); extern void switch_slb(struct task_struct *tsk, struct mm_struct *mm); |
