Skip to content

Commit

Permalink
nds32: Cache and TLB routines
Browse files Browse the repository at this point in the history
This patch contains cache and TLB maintenance functions.

Signed-off-by: Vincent Chen <vincentc@andestech.com>
Signed-off-by: Greentime Hu <greentime@andestech.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
  • Loading branch information
Greentime Hu committed Feb 22, 2018
1 parent 664eec4 commit 7de9cf4
Show file tree
Hide file tree
Showing 12 changed files with 1,224 additions and 0 deletions.
12 changes: 12 additions & 0 deletions arch/nds32/include/asm/cache.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2005-2017 Andes Technology Corporation

#ifndef __NDS32_CACHE_H__
#define __NDS32_CACHE_H__

#define L1_CACHE_BYTES 32
#define L1_CACHE_SHIFT 5

#define ARCH_DMA_MINALIGN L1_CACHE_BYTES

#endif /* __NDS32_CACHE_H__ */
13 changes: 13 additions & 0 deletions arch/nds32/include/asm/cache_info.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2005-2017 Andes Technology Corporation

struct cache_info {
unsigned char ways;
unsigned char line_size;
unsigned short sets;
unsigned short size;
#if defined(CONFIG_CPU_CACHE_ALIASING)
unsigned short aliasing_num;
unsigned int aliasing_mask;
#endif
};
44 changes: 44 additions & 0 deletions arch/nds32/include/asm/cacheflush.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2005-2017 Andes Technology Corporation

#ifndef __NDS32_CACHEFLUSH_H__
#define __NDS32_CACHEFLUSH_H__

#include <linux/mm.h>

#define PG_dcache_dirty PG_arch_1

#ifdef CONFIG_CPU_CACHE_ALIASING
void flush_cache_mm(struct mm_struct *mm);
void flush_cache_dup_mm(struct mm_struct *mm);
void flush_cache_range(struct vm_area_struct *vma,
unsigned long start, unsigned long end);
void flush_cache_page(struct vm_area_struct *vma,
unsigned long addr, unsigned long pfn);
void flush_cache_kmaps(void);
void flush_cache_vmap(unsigned long start, unsigned long end);
void flush_cache_vunmap(unsigned long start, unsigned long end);

#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
void flush_dcache_page(struct page *page);
void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
unsigned long vaddr, void *dst, void *src, int len);
void copy_from_user_page(struct vm_area_struct *vma, struct page *page,
unsigned long vaddr, void *dst, void *src, int len);

#define ARCH_HAS_FLUSH_ANON_PAGE
void flush_anon_page(struct vm_area_struct *vma,
struct page *page, unsigned long vaddr);

#define ARCH_HAS_FLUSH_KERNEL_DCACHE_PAGE
void flush_kernel_dcache_page(struct page *page);
void flush_icache_range(unsigned long start, unsigned long end);
void flush_icache_page(struct vm_area_struct *vma, struct page *page);
#define flush_dcache_mmap_lock(mapping) spin_lock_irq(&(mapping)->tree_lock)
#define flush_dcache_mmap_unlock(mapping) spin_unlock_irq(&(mapping)->tree_lock)

#else
#include <asm-generic/cacheflush.h>
#endif

#endif /* __NDS32_CACHEFLUSH_H__ */
68 changes: 68 additions & 0 deletions arch/nds32/include/asm/mmu_context.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2005-2017 Andes Technology Corporation

#ifndef __ASM_NDS32_MMU_CONTEXT_H
#define __ASM_NDS32_MMU_CONTEXT_H

#include <linux/spinlock.h>
#include <asm/tlbflush.h>
#include <asm/proc-fns.h>
#include <asm-generic/mm_hooks.h>

static inline int
init_new_context(struct task_struct *tsk, struct mm_struct *mm)
{
mm->context.id = 0;
return 0;
}

#define destroy_context(mm) do { } while(0)

#define CID_BITS 9
extern spinlock_t cid_lock;
extern unsigned int cpu_last_cid;

static inline void __new_context(struct mm_struct *mm)
{
unsigned int cid;
unsigned long flags;

spin_lock_irqsave(&cid_lock, flags);
cid = cpu_last_cid;
cpu_last_cid += 1 << TLB_MISC_offCID;
if (cpu_last_cid == 0)
cpu_last_cid = 1 << TLB_MISC_offCID << CID_BITS;

if ((cid & TLB_MISC_mskCID) == 0)
flush_tlb_all();
spin_unlock_irqrestore(&cid_lock, flags);

mm->context.id = cid;
}

static inline void check_context(struct mm_struct *mm)
{
if (unlikely
((mm->context.id ^ cpu_last_cid) >> TLB_MISC_offCID >> CID_BITS))
__new_context(mm);
}

static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
{
}

static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
struct task_struct *tsk)
{
unsigned int cpu = smp_processor_id();

if (!cpumask_test_and_set_cpu(cpu, mm_cpumask(next)) || prev != next) {
check_context(next);
cpu_switch_mm(next);
}
}

#define deactivate_mm(tsk,mm) do { } while (0)
#define activate_mm(prev,next) switch_mm(prev, next, NULL)

#endif
44 changes: 44 additions & 0 deletions arch/nds32/include/asm/proc-fns.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2005-2017 Andes Technology Corporation

#ifndef __NDS32_PROCFNS_H__
#define __NDS32_PROCFNS_H__

#ifdef __KERNEL__
#include <asm/page.h>

struct mm_struct;
struct vm_area_struct;
extern void cpu_proc_init(void);
extern void cpu_proc_fin(void);
extern void cpu_do_idle(void);
extern void cpu_reset(unsigned long reset);
extern void cpu_switch_mm(struct mm_struct *mm);

extern void cpu_dcache_inval_all(void);
extern void cpu_dcache_wbinval_all(void);
extern void cpu_dcache_inval_page(unsigned long page);
extern void cpu_dcache_wb_page(unsigned long page);
extern void cpu_dcache_wbinval_page(unsigned long page);
extern void cpu_dcache_inval_range(unsigned long start, unsigned long end);
extern void cpu_dcache_wb_range(unsigned long start, unsigned long end);
extern void cpu_dcache_wbinval_range(unsigned long start, unsigned long end);

extern void cpu_icache_inval_all(void);
extern void cpu_icache_inval_page(unsigned long page);
extern void cpu_icache_inval_range(unsigned long start, unsigned long end);

extern void cpu_cache_wbinval_page(unsigned long page, int flushi);
extern void cpu_cache_wbinval_range(unsigned long start,
unsigned long end, int flushi);
extern void cpu_cache_wbinval_range_check(struct vm_area_struct *vma,
unsigned long start,
unsigned long end, bool flushi,
bool wbd);

extern void cpu_dma_wb_range(unsigned long start, unsigned long end);
extern void cpu_dma_inval_range(unsigned long start, unsigned long end);
extern void cpu_dma_wbinval_range(unsigned long start, unsigned long end);

#endif /* __KERNEL__ */
#endif /* __NDS32_PROCFNS_H__ */
28 changes: 28 additions & 0 deletions arch/nds32/include/asm/tlb.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2005-2017 Andes Technology Corporation

#ifndef __ASMNDS32_TLB_H
#define __ASMNDS32_TLB_H

#define tlb_start_vma(tlb,vma) \
do { \
if (!tlb->fullmm) \
flush_cache_range(vma, vma->vm_start, vma->vm_end); \
} while (0)

#define tlb_end_vma(tlb,vma) \
do { \
if(!tlb->fullmm) \
flush_tlb_range(vma, vma->vm_start, vma->vm_end); \
} while (0)

#define __tlb_remove_tlb_entry(tlb, pte, addr) do { } while (0)

#define tlb_flush(tlb) flush_tlb_mm((tlb)->mm)

#include <asm-generic/tlb.h>

#define __pte_free_tlb(tlb, pte, addr) pte_free((tlb)->mm, pte)
#define __pmd_free_tlb(tlb, pmd, addr) pmd_free((tln)->mm, pmd)

#endif
47 changes: 47 additions & 0 deletions arch/nds32/include/asm/tlbflush.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2005-2017 Andes Technology Corporation

#ifndef _ASMNDS32_TLBFLUSH_H
#define _ASMNDS32_TLBFLUSH_H

#include <linux/spinlock.h>
#include <linux/mm.h>
#include <nds32_intrinsic.h>

static inline void local_flush_tlb_all(void)
{
__nds32__tlbop_flua();
__nds32__isb();
}

static inline void local_flush_tlb_mm(struct mm_struct *mm)
{
__nds32__tlbop_flua();
__nds32__isb();
}

static inline void local_flush_tlb_kernel_range(unsigned long start,
unsigned long end)
{
while (start < end) {
__nds32__tlbop_inv(start);
__nds32__isb();
start += PAGE_SIZE;
}
}

void local_flush_tlb_range(struct vm_area_struct *vma,
unsigned long start, unsigned long end);
void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long addr);

#define flush_tlb_all local_flush_tlb_all
#define flush_tlb_mm local_flush_tlb_mm
#define flush_tlb_range local_flush_tlb_range
#define flush_tlb_page local_flush_tlb_page
#define flush_tlb_kernel_range local_flush_tlb_kernel_range

void update_mmu_cache(struct vm_area_struct *vma,
unsigned long address, pte_t * pte);
void tlb_migrate_finish(struct mm_struct *mm);

#endif
14 changes: 14 additions & 0 deletions arch/nds32/include/uapi/asm/cachectl.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 1994, 1995, 1996 by Ralf Baechle
// Copyright (C) 2005-2017 Andes Technology Corporation
#ifndef _ASM_CACHECTL
#define _ASM_CACHECTL

/*
* Options for cacheflush system call
*/
#define ICACHE 0 /* flush instruction cache */
#define DCACHE 1 /* writeback and flush data cache */
#define BCACHE 2 /* flush instruction cache + writeback and flush data cache */

#endif /* _ASM_CACHECTL */
49 changes: 49 additions & 0 deletions arch/nds32/kernel/cacheinfo.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2005-2017 Andes Technology Corporation

#include <linux/bitops.h>
#include <linux/cacheinfo.h>
#include <linux/cpu.h>

static void ci_leaf_init(struct cacheinfo *this_leaf,
enum cache_type type, unsigned int level)
{
char cache_type = (type & CACHE_TYPE_INST ? ICACHE : DCACHE);

this_leaf->level = level;
this_leaf->type = type;
this_leaf->coherency_line_size = CACHE_LINE_SIZE(cache_type);
this_leaf->number_of_sets = CACHE_SET(cache_type);;
this_leaf->ways_of_associativity = CACHE_WAY(cache_type);
this_leaf->size = this_leaf->number_of_sets *
this_leaf->coherency_line_size * this_leaf->ways_of_associativity;
#if defined(CONFIG_CPU_DCACHE_WRITETHROUGH)
this_leaf->attributes = CACHE_WRITE_THROUGH;
#else
this_leaf->attributes = CACHE_WRITE_BACK;
#endif
}

int init_cache_level(unsigned int cpu)
{
struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);

/* Only 1 level and I/D cache seperate. */
this_cpu_ci->num_levels = 1;
this_cpu_ci->num_leaves = 2;
return 0;
}

int populate_cache_leaves(unsigned int cpu)
{
unsigned int level, idx;
struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
struct cacheinfo *this_leaf = this_cpu_ci->info_list;

for (idx = 0, level = 1; level <= this_cpu_ci->num_levels &&
idx < this_cpu_ci->num_leaves; idx++, level++) {
ci_leaf_init(this_leaf++, CACHE_TYPE_DATA, level);
ci_leaf_init(this_leaf++, CACHE_TYPE_INST, level);
}
return 0;
}
Loading

0 comments on commit 7de9cf4

Please sign in to comment.