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

Commit 8d20a541 authored by Mikael Starvik's avatar Mikael Starvik Committed by Linus Torvalds
Browse files

[PATCH] CRIS update: SMP



Patches to support SMP.

* Each CPU has its own current_pgd.
* flush_tlb_range is implemented as flush_tlb_mm.
* Atomic operations implemented with spinlocks.
* Semaphores implemented with spinlocks.

Signed-off-by: default avatarMikael Starvik <starvik@axis.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 21783c97
Loading
Loading
Loading
Loading
+2 −24
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/arch/svinto.h>
#include <asm/mmu_context.h>

/* debug of low-level TLB reload */
#undef DEBUG
@@ -24,8 +25,6 @@
#define D(x)
#endif

extern volatile pgd_t *current_pgd;

extern const struct exception_table_entry
	*search_exception_tables(unsigned long addr);

@@ -46,7 +45,7 @@ handle_mmu_bus_fault(struct pt_regs *regs)
	int page_id;
	int acc, inv;
#endif
	pgd_t* pgd = (pgd_t*)current_pgd;
	pgd_t* pgd = (pgd_t*)per_cpu(current_pgd, smp_processor_id());
	pmd_t *pmd;
	pte_t pte;
	int miss, we, writeac;
@@ -94,24 +93,3 @@ handle_mmu_bus_fault(struct pt_regs *regs)
	*R_TLB_LO = pte_val(pte);
	local_irq_restore(flags);
}

/* Called from arch/cris/mm/fault.c to find fixup code. */
int
find_fixup_code(struct pt_regs *regs)
{
	const struct exception_table_entry *fixup;

	if ((fixup = search_exception_tables(regs->irp)) != 0) {
		/* Adjust the instruction pointer in the stackframe. */
		regs->irp = fixup->fixup;
		
		/* 
		 * Don't return by restoring the CPU state, so switch
		 * frame-type. 
		 */
		regs->frametype = CRIS_FRAME_NORMAL;
		return 1;
	}

	return 0;
}
+1 −1
Original line number Diff line number Diff line
@@ -42,7 +42,7 @@ paging_init(void)
	 *  switch_mm)
	 */

	current_pgd = init_mm.pgd;
	per_cpu(current_pgd, smp_processor_id()) = init_mm.pgd;

	/* initialise the TLB (tlb.c) */

+1 −48
Original line number Diff line number Diff line
@@ -139,53 +139,6 @@ flush_tlb_page(struct vm_area_struct *vma,
	local_irq_restore(flags);
}

/* invalidate a page range */

void
flush_tlb_range(struct vm_area_struct *vma, 
		unsigned long start,
		unsigned long end)
{
	struct mm_struct *mm = vma->vm_mm;
	int page_id = mm->context.page_id;
	int i;
	unsigned long flags;

	D(printk("tlb: flush range %p<->%p in context %d (%p)\n",
		 start, end, page_id, mm));

	if(page_id == NO_CONTEXT)
		return;

	start &= PAGE_MASK;  /* probably not necessary */
	end &= PAGE_MASK;    /* dito */

	/* invalidate those TLB entries that match both the mm context
	 * and the virtual address range
	 */

	local_save_flags(flags);
	local_irq_disable();
	for(i = 0; i < NUM_TLB_ENTRIES; i++) {
		unsigned long tlb_hi, vpn;
		*R_TLB_SELECT = IO_FIELD(R_TLB_SELECT, index, i);
		tlb_hi = *R_TLB_HI;
		vpn = tlb_hi & PAGE_MASK;
		if (IO_EXTRACT(R_TLB_HI, page_id, tlb_hi) == page_id &&
		    vpn >= start && vpn < end) {
			*R_TLB_HI = ( IO_FIELD(R_TLB_HI, page_id, INVALID_PAGEID ) |
				      IO_FIELD(R_TLB_HI, vpn,     i & 0xf ) );
			
			*R_TLB_LO = ( IO_STATE(R_TLB_LO, global,no  ) |
				      IO_STATE(R_TLB_LO, valid, no  ) |
				      IO_STATE(R_TLB_LO, kernel,no  ) |
				      IO_STATE(R_TLB_LO, we,    no  ) |
				      IO_FIELD(R_TLB_LO, pfn,   0   ) );
		}
	}
	local_irq_restore(flags);
}

/* dump the entire TLB for debug purposes */

#if 0
@@ -237,7 +190,7 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next,
	 * the pgd.
	 */

	current_pgd = next->pgd;
	per_cpu(current_pgd, smp_processor_id()) = next->pgd;

	/* switch context in the MMU */
	
+7 −0
Original line number Diff line number Diff line
#ifndef __ASM_CRIS_ARCH_ATOMIC__
#define __ASM_CRIS_ARCH_ATOMIC__

#define cris_atomic_save(addr, flags) local_irq_save(flags);
#define cris_atomic_restore(addr, flags) local_irq_restore(flags);

#endif
+24 −42
Original line number Diff line number Diff line
@@ -4,21 +4,14 @@
#define __ASM_CRIS_ATOMIC__

#include <asm/system.h>
#include <asm/arch/atomic.h>

/*
 * Atomic operations that C can't guarantee us.  Useful for
 * resource counting etc..
 */

/*
 * Make sure gcc doesn't try to be clever and move things around
 * on us. We need to use _exactly_ the address the user gave us,
 * not some alias that contains the same information.
 */

#define __atomic_fool_gcc(x) (*(struct { int a[100]; } *)x)

typedef struct { int counter; } atomic_t;
typedef struct { volatile int counter; } atomic_t;

#define ATOMIC_INIT(i)  { (i) }

@@ -30,29 +23,26 @@ typedef struct { int counter; } atomic_t;
extern __inline__ void atomic_add(int i, volatile atomic_t *v)
{
	unsigned long flags;
	local_save_flags(flags);
	local_irq_disable();
	cris_atomic_save(v, flags);
	v->counter += i;
	local_irq_restore(flags);
	cris_atomic_restore(v, flags);
}

extern __inline__ void atomic_sub(int i, volatile atomic_t *v)
{
	unsigned long flags;
	local_save_flags(flags);
	local_irq_disable();
	cris_atomic_save(v, flags);
	v->counter -= i;
	local_irq_restore(flags);
	cris_atomic_restore(v, flags);
}

extern __inline__ int atomic_add_return(int i, volatile atomic_t *v)
{
	unsigned long flags;
	int retval;
	local_save_flags(flags);
	local_irq_disable();
	cris_atomic_save(v, flags);
	retval = (v->counter += i);
	local_irq_restore(flags);
	cris_atomic_restore(v, flags);
	return retval;
}

@@ -62,10 +52,9 @@ extern __inline__ int atomic_sub_return(int i, volatile atomic_t *v)
{
	unsigned long flags;
	int retval;
	local_save_flags(flags);
	local_irq_disable();
	cris_atomic_save(v, flags);
	retval = (v->counter -= i);
	local_irq_restore(flags);
	cris_atomic_restore(v, flags);
	return retval;
}

@@ -73,39 +62,35 @@ extern __inline__ int atomic_sub_and_test(int i, volatile atomic_t *v)
{
	int retval;
	unsigned long flags;
	local_save_flags(flags);
	local_irq_disable();
	cris_atomic_save(v, flags);
	retval = (v->counter -= i) == 0;
	local_irq_restore(flags);
	cris_atomic_restore(v, flags);
	return retval;
}

extern __inline__ void atomic_inc(volatile atomic_t *v)
{
	unsigned long flags;
	local_save_flags(flags);
	local_irq_disable();
	cris_atomic_save(v, flags);
	(v->counter)++;
	local_irq_restore(flags);
	cris_atomic_restore(v, flags);
}

extern __inline__ void atomic_dec(volatile atomic_t *v)
{
	unsigned long flags;
	local_save_flags(flags);
	local_irq_disable();
	cris_atomic_save(v, flags);
	(v->counter)--;
	local_irq_restore(flags);
	cris_atomic_restore(v, flags);
}

extern __inline__ int atomic_inc_return(volatile atomic_t *v)
{
	unsigned long flags;
	int retval;
	local_save_flags(flags);
	local_irq_disable();
	cris_atomic_save(v, flags);
	retval = (v->counter)++;
	local_irq_restore(flags);
	cris_atomic_restore(v, flags);
	return retval;
}

@@ -113,20 +98,18 @@ extern __inline__ int atomic_dec_return(volatile atomic_t *v)
{
	unsigned long flags;
	int retval;
	local_save_flags(flags);
	local_irq_disable();
	cris_atomic_save(v, flags);
	retval = (v->counter)--;
	local_irq_restore(flags);
	cris_atomic_restore(v, flags);
	return retval;
}
extern __inline__ int atomic_dec_and_test(volatile atomic_t *v)
{
	int retval;
	unsigned long flags;
	local_save_flags(flags);
	local_irq_disable();
	cris_atomic_save(v, flags);
	retval = --(v->counter) == 0;
	local_irq_restore(flags);
	cris_atomic_restore(v, flags);
	return retval;
}

@@ -134,10 +117,9 @@ extern __inline__ int atomic_inc_and_test(volatile atomic_t *v)
{
	int retval;
	unsigned long flags;
	local_save_flags(flags);
	local_irq_disable();
	cris_atomic_save(v, flags);
	retval = ++(v->counter) == 0;
	local_irq_restore(flags);
	cris_atomic_restore(v, flags);
	return retval;
}

Loading