Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit aec5e0e1 authored by Paul Mundt's avatar Paul Mundt
Browse files

sh: Use a per-cpu ASID cache.



Previously this was implemented using a global cache, cache
this per-CPU instead and bump up the number of context IDs to
match NR_CPUS.

Signed-off-by: default avatarPaul Mundt <lethal@linux-sh.org>
parent 506b85f4
Loading
Loading
Loading
Loading
+9 −2
Original line number Diff line number Diff line
@@ -3,7 +3,7 @@
 *
 * CPU init code
 *
 * Copyright (C) 2002, 2003  Paul Mundt
 * Copyright (C) 2002 - 2006  Paul Mundt
 * Copyright (C) 2003  Richard Curnow
 *
 * This file is subject to the terms and conditions of the GNU General Public
@@ -12,6 +12,8 @@
 */
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <asm/mmu_context.h>
#include <asm/processor.h>
#include <asm/uaccess.h>
#include <asm/page.h>
@@ -218,6 +220,12 @@ asmlinkage void __init sh_cpu_init(void)
		clear_used_math();
	}

	/*
	 * Initialize the per-CPU ASID cache very early, since the
	 * TLB flushing routines depend on this being setup.
	 */
	current_cpu_data.asid_cache = NO_CONTEXT;

#ifdef CONFIG_SH_DSP
	/* Probe for DSP */
	dsp_init();
@@ -240,4 +248,3 @@ asmlinkage void __init sh_cpu_init(void)
	ubc_wakeup();
#endif
}
+28 −38
Original line number Diff line number Diff line
/* $Id: process.c,v 1.28 2004/05/05 16:54:23 lethal Exp $
/*
 * arch/sh/kernel/process.c
 *
 *  linux/arch/sh/kernel/process.c
 * This file handles the architecture-dependent parts of process handling..
 *
 *  Copyright (C) 1995  Linus Torvalds
 *
 *  SuperH version:  Copyright (C) 1999, 2000  Niibe Yutaka & Kaz Kojima
 *		     Copyright (C) 2006 Lineo Solutions Inc. support SH4A UBC
 *		     Copyright (C) 2002 - 2006  Paul Mundt
 */

/*
 * This file handles the architecture-dependent parts of process handling..
 */

#include <linux/module.h>
#include <linux/unistd.h>
#include <linux/mm.h>
#include <linux/elfcore.h>
#include <linux/a.out.h>
#include <linux/slab.h>
#include <linux/pm.h>
#include <linux/ptrace.h>
#include <linux/kallsyms.h>
#include <linux/kexec.h>

#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/mmu_context.h>
#include <asm/elf.h>
#include <asm/ubc.h>

static int hlt_counter=0;

static int hlt_counter;
int ubc_usercnt = 0;

#define HARD_IDLE_TIMEOUT (HZ / 3)

void (*pm_idle)(void);

void (*pm_power_off)(void);
EXPORT_SYMBOL(pm_power_off);

@@ -44,14 +32,12 @@ void disable_hlt(void)
{
	hlt_counter++;
}

EXPORT_SYMBOL(disable_hlt);

void enable_hlt(void)
{
	hlt_counter--;
}

EXPORT_SYMBOL(enable_hlt);

void default_idle(void)
@@ -152,8 +138,9 @@ __asm__(".align 5\n"
	".align 2\n\t"
	"1:.long do_exit");

/* Don't use this in BL=1(cli).  Or else, CPU resets! */
int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
{	/* Don't use this in BL=1(cli).  Or else, CPU resets! */
{
	struct pt_regs regs;

	memset(&regs, 0, sizeof(regs));
@@ -164,7 +151,8 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
	regs.sr = (1 << 30);

	/* Ok, create the new process.. */
	return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
	return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0,
		       &regs, 0, NULL, NULL);
}

/*
@@ -224,8 +212,7 @@ int dump_task_regs(struct task_struct *tsk, elf_gregset_t *regs)
	return 1;
}

int
dump_task_fpu (struct task_struct *tsk, elf_fpregset_t *fpu)
int dump_task_fpu(struct task_struct *tsk, elf_fpregset_t *fpu)
{
	int fpvalid = 0;

@@ -263,12 +250,14 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
		childregs->regs[15] = usp;
		ti->addr_limit = USER_DS;
	} else {
		childregs->regs[15] = (unsigned long)task_stack_page(p) + THREAD_SIZE;
		childregs->regs[15] = (unsigned long)task_stack_page(p) +
							THREAD_SIZE;
		ti->addr_limit = KERNEL_DS;
	}
        if (clone_flags & CLONE_SETTLS) {

        if (clone_flags & CLONE_SETTLS)
		childregs->gbr = childregs->regs[0];
	}

	childregs->regs[0] = 0; /* Set return value for child */

	p->thread.sp = (unsigned long) childregs;
@@ -280,8 +269,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
}

/* Tracing by user break controller.  */
static void
ubc_set_tracing(int asid, unsigned long pc)
static void ubc_set_tracing(int asid, unsigned long pc)
{
#if defined(CONFIG_CPU_SH4A)
	unsigned long val;
@@ -297,7 +285,7 @@ ubc_set_tracing(int asid, unsigned long pc)
	val = (UBC_CRR_RES | UBC_CRR_PCB | UBC_CRR_BIE);
	ctrl_outl(val, UBC_CRR0);

	/* Read UBC register that we writed last. For chekking UBC Register changed */
	/* Read UBC register that we wrote last, for checking update */
	val = ctrl_inl(UBC_CRR0);

#else	/* CONFIG_CPU_SH4A */
@@ -325,7 +313,8 @@ ubc_set_tracing(int asid, unsigned long pc)
 *	switch_to(x,y) should switch tasks from x to y.
 *
 */
struct task_struct *__switch_to(struct task_struct *prev, struct task_struct *next)
struct task_struct *__switch_to(struct task_struct *prev,
				struct task_struct *next)
{
#if defined(CONFIG_SH_FPU)
	unlazy_fpu(prev, task_pt_regs(prev));
@@ -367,7 +356,7 @@ struct task_struct *__switch_to(struct task_struct *prev, struct task_struct *ne
	else if (next->thread.ubc_pc && next->mm) {
		int asid = 0;
#ifdef CONFIG_MMU
		asid |= next->mm->context.id & MMU_CONTEXT_ASID_MASK;
		asid |= cpu_asid(smp_processor_id(), next->mm);
#endif
		ubc_set_tracing(asid, next->thread.ubc_pc);
	} else {
@@ -405,7 +394,8 @@ asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp,
	if (!newsp)
		newsp = regs->regs[15];
	return do_fork(clone_flags, newsp, regs, 0,
			(int __user *)parent_tidptr, (int __user *)child_tidptr);
			(int __user *)parent_tidptr,
			(int __user *)child_tidptr);
}

/*
+0 −5
Original line number Diff line number Diff line
@@ -39,11 +39,6 @@
DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
pgd_t swapper_pg_dir[PTRS_PER_PGD];

/*
 * Cache of MMU context last used.
 */
unsigned long mmu_context_cache = NO_CONTEXT;

#ifdef CONFIG_MMU
/* It'd be good if these lines were in the standard header file. */
#define START_PFN	(NODE_DATA(0)->bdata->node_boot_start >> PAGE_SHIFT)
+16 −10
Original line number Diff line number Diff line
@@ -16,12 +16,14 @@

void flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
{
	if (vma->vm_mm && vma->vm_mm->context.id != NO_CONTEXT) {
	unsigned int cpu = smp_processor_id();

	if (vma->vm_mm && cpu_context(cpu, vma->vm_mm) != NO_CONTEXT) {
		unsigned long flags;
		unsigned long asid;
		unsigned long saved_asid = MMU_NO_ASID;

		asid = vma->vm_mm->context.id & MMU_CONTEXT_ASID_MASK;
		asid = cpu_asid(cpu, vma->vm_mm);
		page &= PAGE_MASK;

		local_irq_save(flags);
@@ -40,22 +42,23 @@ void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
		     unsigned long end)
{
	struct mm_struct *mm = vma->vm_mm;
	unsigned int cpu = smp_processor_id();

	if (mm->context.id != NO_CONTEXT) {
	if (cpu_context(cpu, mm) != NO_CONTEXT) {
		unsigned long flags;
		int size;

		local_irq_save(flags);
		size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
		if (size > (MMU_NTLB_ENTRIES/4)) { /* Too many TLB to flush */
			mm->context.id = NO_CONTEXT;
			cpu_context(cpu, mm) = NO_CONTEXT;
			if (mm == current->mm)
				activate_context(mm);
				activate_context(mm, cpu);
		} else {
			unsigned long asid;
			unsigned long saved_asid = MMU_NO_ASID;

			asid = mm->context.id & MMU_CONTEXT_ASID_MASK;
			asid = cpu_asid(cpu, mm);
			start &= PAGE_MASK;
			end += (PAGE_SIZE - 1);
			end &= PAGE_MASK;
@@ -76,6 +79,7 @@ void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,

void flush_tlb_kernel_range(unsigned long start, unsigned long end)
{
	unsigned int cpu = smp_processor_id();
	unsigned long flags;
	int size;

@@ -87,7 +91,7 @@ void flush_tlb_kernel_range(unsigned long start, unsigned long end)
		unsigned long asid;
		unsigned long saved_asid = get_asid();

		asid = init_mm.context.id & MMU_CONTEXT_ASID_MASK;
		asid = cpu_asid(cpu, &init_mm);
		start &= PAGE_MASK;
		end += (PAGE_SIZE - 1);
		end &= PAGE_MASK;
@@ -103,15 +107,17 @@ void flush_tlb_kernel_range(unsigned long start, unsigned long end)

void flush_tlb_mm(struct mm_struct *mm)
{
	unsigned int cpu = smp_processor_id();

	/* Invalidate all TLB of this process. */
	/* Instead of invalidating each TLB, we get new MMU context. */
	if (mm->context.id != NO_CONTEXT) {
	if (cpu_context(cpu, mm) != NO_CONTEXT) {
		unsigned long flags;

		local_irq_save(flags);
		mm->context.id = NO_CONTEXT;
		cpu_context(cpu, mm) = NO_CONTEXT;
		if (mm == current->mm)
			activate_context(mm);
			activate_context(mm, cpu);
		local_irq_restore(flags);
	}
}
+7 −13
Original line number Diff line number Diff line
#ifndef __MMU_H
#define __MMU_H

#if !defined(CONFIG_MMU)

typedef struct {
	struct vm_list_struct	*vmlist;
	unsigned long		end_brk;
} mm_context_t;

#else

/* Default "unsigned long" context */
typedef unsigned long mm_context_id_t;
typedef unsigned long mm_context_id_t[NR_CPUS];

typedef struct {
#ifdef CONFIG_MMU
	mm_context_id_t		id;
	void			*vdso;
#else
	struct vm_list_struct	*vmlist;
	unsigned long		end_brk;
#endif
} mm_context_t;

#endif /* CONFIG_MMU */

/*
 * Privileged Space Mapping Buffer (PMB) definitions
 */
Loading