Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 123118
b: refs/heads/master
c: 7752035
h: refs/heads/master
v: v3
  • Loading branch information
Benjamin Herrenschmidt authored and Paul Mackerras committed Dec 21, 2008
1 parent 70a2817 commit 686869e
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 55 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 760ec0e02d8a13d0ed60d99f47879d4aa8ef1910
refs/heads/master: 77520351805cc19ba37394ae33f862ef6d3c2a23
5 changes: 5 additions & 0 deletions trunk/arch/powerpc/kernel/setup_32.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include <asm/time.h>
#include <asm/serial.h>
#include <asm/udbg.h>
#include <asm/mmu_context.h>

#include "setup.h"

Expand Down Expand Up @@ -330,4 +331,8 @@ void __init setup_arch(char **cmdline_p)
if ( ppc_md.progress ) ppc_md.progress("arch: exit", 0x3eab);

paging_init();

/* Initialize the MMU context management stuff */
mmu_context_init();

}
4 changes: 0 additions & 4 deletions trunk/arch/powerpc/mm/init_32.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@
#include <asm/pgalloc.h>
#include <asm/prom.h>
#include <asm/io.h>
#include <asm/mmu_context.h>
#include <asm/pgtable.h>
#include <asm/mmu.h>
#include <asm/smp.h>
Expand Down Expand Up @@ -180,9 +179,6 @@ void __init MMU_init(void)
if (ppc_md.progress)
ppc_md.progress("MMU:setio", 0x302);

/* Initialize the context management stuff */
mmu_context_init();

if (ppc_md.progress)
ppc_md.progress("MMU:exit", 0x211);

Expand Down
161 changes: 111 additions & 50 deletions trunk/arch/powerpc/mm/mmu_context_nohash.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,54 +28,30 @@
#undef DEBUG
#define DEBUG_STEAL_ONLY
#undef DEBUG_MAP_CONSISTENCY
/*#define DEBUG_CLAMP_LAST_CONTEXT 15 */

#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/bootmem.h>
#include <linux/notifier.h>
#include <linux/cpu.h>

#include <asm/mmu_context.h>
#include <asm/tlbflush.h>
#include <linux/spinlock.h>

/*
* The MPC8xx has only 16 contexts. We rotate through them on each
* task switch. A better way would be to keep track of tasks that
* own contexts, and implement an LRU usage. That way very active
* tasks don't always have to pay the TLB reload overhead. The
* kernel pages are mapped shared, so the kernel can run on behalf
* of any task that makes a kernel entry. Shared does not mean they
* are not protected, just that the ASID comparison is not performed.
* -- Dan
*
* The IBM4xx has 256 contexts, so we can just rotate through these
* as a way of "switching" contexts. If the TID of the TLB is zero,
* the PID/TID comparison is disabled, so we can use a TID of zero
* to represent all kernel pages as shared among all contexts.
* -- Dan
*/

#ifdef CONFIG_8xx
#define LAST_CONTEXT 15
#define FIRST_CONTEXT 0

#elif defined(CONFIG_4xx)
#define LAST_CONTEXT 255
#define FIRST_CONTEXT 1

#elif defined(CONFIG_E200) || defined(CONFIG_E500)
#define LAST_CONTEXT 255
#define FIRST_CONTEXT 1

#else
#error Unsupported processor type
#endif

static unsigned int first_context, last_context;
static unsigned int next_context, nr_free_contexts;
static unsigned long context_map[LAST_CONTEXT / BITS_PER_LONG + 1];
static unsigned long stale_map[NR_CPUS][LAST_CONTEXT / BITS_PER_LONG + 1];
static struct mm_struct *context_mm[LAST_CONTEXT+1];
static unsigned long *context_map;
static unsigned long *stale_map[NR_CPUS];
static struct mm_struct **context_mm;
static spinlock_t context_lock = SPIN_LOCK_UNLOCKED;

#define CTX_MAP_SIZE \
(sizeof(unsigned long) * (last_context / BITS_PER_LONG + 1))


/* Steal a context from a task that has one at the moment.
*
* This is used when we are running out of available PID numbers
Expand All @@ -98,7 +74,7 @@ static unsigned int steal_context_smp(unsigned int id)
unsigned int cpu, max;

again:
max = LAST_CONTEXT - FIRST_CONTEXT;
max = last_context - first_context;

/* Attempt to free next_context first and then loop until we manage */
while (max--) {
Expand All @@ -110,8 +86,8 @@ static unsigned int steal_context_smp(unsigned int id)
*/
if (mm->context.active) {
id++;
if (id > LAST_CONTEXT)
id = FIRST_CONTEXT;
if (id > last_context)
id = first_context;
continue;
}
pr_debug("[%d] steal context %d from mm @%p\n",
Expand Down Expand Up @@ -169,7 +145,7 @@ static void context_check_map(void)
unsigned int id, nrf, nact;

nrf = nact = 0;
for (id = FIRST_CONTEXT; id <= LAST_CONTEXT; id++) {
for (id = first_context; id <= last_context; id++) {
int used = test_bit(id, context_map);
if (!used)
nrf++;
Expand All @@ -187,6 +163,8 @@ static void context_check_map(void)
if (nact > num_online_cpus())
pr_err("MMU: More active contexts than CPUs ! (%d vs %d)\n",
nact, num_online_cpus());
if (first_context > 0 && !test_bit(0, context_map))
pr_err("MMU: Context 0 has been freed !!!\n");
}
#else
static void context_check_map(void) { }
Expand All @@ -209,6 +187,10 @@ void switch_mmu_context(struct mm_struct *prev, struct mm_struct *next)
/* Mark us active and the previous one not anymore */
next->context.active++;
if (prev) {
#ifndef DEBUG_STEAL_ONLY
pr_debug(" old context %p active was: %d\n",
prev, prev->context.active);
#endif
WARN_ON(prev->context.active < 1);
prev->context.active--;
}
Expand All @@ -221,8 +203,8 @@ void switch_mmu_context(struct mm_struct *prev, struct mm_struct *next)

/* We really don't have a context, let's try to acquire one */
id = next_context;
if (id > LAST_CONTEXT)
id = FIRST_CONTEXT;
if (id > last_context)
id = first_context;
map = context_map;

/* No more free contexts, let's try to steal one */
Expand All @@ -240,9 +222,9 @@ void switch_mmu_context(struct mm_struct *prev, struct mm_struct *next)

/* We know there's at least one free context, try to find it */
while (__test_and_set_bit(id, map)) {
id = find_next_zero_bit(map, LAST_CONTEXT+1, id);
if (id > LAST_CONTEXT)
id = FIRST_CONTEXT;
id = find_next_zero_bit(map, last_context+1, id);
if (id > last_context)
id = first_context;
}
stolen:
next_context = id + 1;
Expand Down Expand Up @@ -311,6 +293,42 @@ void destroy_context(struct mm_struct *mm)
spin_unlock(&context_lock);
}

#ifdef CONFIG_SMP

static int __cpuinit mmu_context_cpu_notify(struct notifier_block *self,
unsigned long action, void *hcpu)
{
unsigned int cpu = (unsigned int)(long)hcpu;

/* We don't touch CPU 0 map, it's allocated at aboot and kept
* around forever
*/
if (cpu == 0)
return NOTIFY_OK;

switch (action) {
case CPU_ONLINE:
case CPU_ONLINE_FROZEN:
pr_debug("MMU: Allocating stale context map for CPU %d\n", cpu);
stale_map[cpu] = kzalloc(CTX_MAP_SIZE, GFP_KERNEL);
break;
#ifdef CONFIG_HOTPLUG_CPU
case CPU_DEAD:
case CPU_DEAD_FROZEN:
pr_debug("MMU: Freeing stale context map for CPU %d\n", cpu);
kfree(stale_map[cpu]);
stale_map[cpu] = NULL;
break;
#endif
}
return NOTIFY_OK;
}

static struct notifier_block __cpuinitdata mmu_context_cpu_nb = {
.notifier_call = mmu_context_cpu_notify,
};

#endif /* CONFIG_SMP */

/*
* Initialize the context management stuff.
Expand All @@ -323,14 +341,57 @@ void __init mmu_context_init(void)
*/
init_mm.context.active = NR_CPUS;

/*
* The MPC8xx has only 16 contexts. We rotate through them on each
* task switch. A better way would be to keep track of tasks that
* own contexts, and implement an LRU usage. That way very active
* tasks don't always have to pay the TLB reload overhead. The
* kernel pages are mapped shared, so the kernel can run on behalf
* of any task that makes a kernel entry. Shared does not mean they
* are not protected, just that the ASID comparison is not performed.
* -- Dan
*
* The IBM4xx has 256 contexts, so we can just rotate through these
* as a way of "switching" contexts. If the TID of the TLB is zero,
* the PID/TID comparison is disabled, so we can use a TID of zero
* to represent all kernel pages as shared among all contexts.
* -- Dan
*/
if (mmu_has_feature(MMU_FTR_TYPE_8xx)) {
first_context = 0;
last_context = 15;
} else {
first_context = 1;
last_context = 255;
}

#ifdef DEBUG_CLAMP_LAST_CONTEXT
last_context = DEBUG_CLAMP_LAST_CONTEXT;
#endif
/*
* Allocate the maps used by context management
*/
context_map = alloc_bootmem(CTX_MAP_SIZE);
context_mm = alloc_bootmem(sizeof(void *) * (last_context + 1));
stale_map[0] = alloc_bootmem(CTX_MAP_SIZE);

#ifdef CONFIG_SMP
register_cpu_notifier(&mmu_context_cpu_nb);
#endif

printk(KERN_INFO
"MMU: Allocated %d bytes of context maps for %d contexts\n",
2 * CTX_MAP_SIZE + (sizeof(void *) * (last_context + 1)),
last_context - first_context + 1);

/*
* Some processors have too few contexts to reserve one for
* init_mm, and require using context 0 for a normal task.
* Other processors reserve the use of context zero for the kernel.
* This code assumes FIRST_CONTEXT < 32.
* This code assumes first_context < 32.
*/
context_map[0] = (1 << FIRST_CONTEXT) - 1;
next_context = FIRST_CONTEXT;
nr_free_contexts = LAST_CONTEXT - FIRST_CONTEXT + 1;
context_map[0] = (1 << first_context) - 1;
next_context = first_context;
nr_free_contexts = last_context - first_context + 1;
}

0 comments on commit 686869e

Please sign in to comment.