162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
362306a36Sopenharmony_ci * License.  See the file "COPYING" in the main directory of this archive
462306a36Sopenharmony_ci * for more details.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright (C) 2001 - 2013 Tensilica Inc.
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#ifndef _XTENSA_TLBFLUSH_H
1062306a36Sopenharmony_ci#define _XTENSA_TLBFLUSH_H
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <linux/stringify.h>
1362306a36Sopenharmony_ci#include <asm/processor.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#define DTLB_WAY_PGD	7
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#define ITLB_ARF_WAYS	4
1862306a36Sopenharmony_ci#define DTLB_ARF_WAYS	4
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#define ITLB_HIT_BIT	3
2162306a36Sopenharmony_ci#define DTLB_HIT_BIT	4
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#ifndef __ASSEMBLY__
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci/* TLB flushing:
2662306a36Sopenharmony_ci *
2762306a36Sopenharmony_ci *  - flush_tlb_all() flushes all processes TLB entries
2862306a36Sopenharmony_ci *  - flush_tlb_mm(mm) flushes the specified mm context TLB entries
2962306a36Sopenharmony_ci *  - flush_tlb_page(vma, page) flushes a single page
3062306a36Sopenharmony_ci *  - flush_tlb_range(vma, vmaddr, end) flushes a range of pages
3162306a36Sopenharmony_ci */
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_civoid local_flush_tlb_all(void);
3462306a36Sopenharmony_civoid local_flush_tlb_mm(struct mm_struct *mm);
3562306a36Sopenharmony_civoid local_flush_tlb_page(struct vm_area_struct *vma,
3662306a36Sopenharmony_ci		unsigned long page);
3762306a36Sopenharmony_civoid local_flush_tlb_range(struct vm_area_struct *vma,
3862306a36Sopenharmony_ci		unsigned long start, unsigned long end);
3962306a36Sopenharmony_civoid local_flush_tlb_kernel_range(unsigned long start, unsigned long end);
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci#ifdef CONFIG_SMP
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_civoid flush_tlb_all(void);
4462306a36Sopenharmony_civoid flush_tlb_mm(struct mm_struct *);
4562306a36Sopenharmony_civoid flush_tlb_page(struct vm_area_struct *, unsigned long);
4662306a36Sopenharmony_civoid flush_tlb_range(struct vm_area_struct *, unsigned long,
4762306a36Sopenharmony_ci		unsigned long);
4862306a36Sopenharmony_civoid flush_tlb_kernel_range(unsigned long start, unsigned long end);
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci#else /* !CONFIG_SMP */
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci#define flush_tlb_all()			   local_flush_tlb_all()
5362306a36Sopenharmony_ci#define flush_tlb_mm(mm)		   local_flush_tlb_mm(mm)
5462306a36Sopenharmony_ci#define flush_tlb_page(vma, page)	   local_flush_tlb_page(vma, page)
5562306a36Sopenharmony_ci#define flush_tlb_range(vma, vmaddr, end)  local_flush_tlb_range(vma, vmaddr, \
5662306a36Sopenharmony_ci								 end)
5762306a36Sopenharmony_ci#define flush_tlb_kernel_range(start, end) local_flush_tlb_kernel_range(start, \
5862306a36Sopenharmony_ci									end)
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci#endif /* CONFIG_SMP */
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci/* TLB operations. */
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cistatic inline unsigned long itlb_probe(unsigned long addr)
6562306a36Sopenharmony_ci{
6662306a36Sopenharmony_ci	unsigned long tmp;
6762306a36Sopenharmony_ci	__asm__ __volatile__("pitlb  %0, %1\n\t" : "=a" (tmp) : "a" (addr));
6862306a36Sopenharmony_ci	return tmp;
6962306a36Sopenharmony_ci}
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_cistatic inline unsigned long dtlb_probe(unsigned long addr)
7262306a36Sopenharmony_ci{
7362306a36Sopenharmony_ci	unsigned long tmp;
7462306a36Sopenharmony_ci	__asm__ __volatile__("pdtlb  %0, %1\n\t" : "=a" (tmp) : "a" (addr));
7562306a36Sopenharmony_ci	return tmp;
7662306a36Sopenharmony_ci}
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cistatic inline void invalidate_itlb_entry (unsigned long probe)
7962306a36Sopenharmony_ci{
8062306a36Sopenharmony_ci	__asm__ __volatile__("iitlb  %0; isync\n\t" : : "a" (probe));
8162306a36Sopenharmony_ci}
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_cistatic inline void invalidate_dtlb_entry (unsigned long probe)
8462306a36Sopenharmony_ci{
8562306a36Sopenharmony_ci	__asm__ __volatile__("idtlb  %0; dsync\n\t" : : "a" (probe));
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci/* Use the .._no_isync functions with caution.  Generally, these are
8962306a36Sopenharmony_ci * handy for bulk invalidates followed by a single 'isync'.  The
9062306a36Sopenharmony_ci * caller must follow up with an 'isync', which can be relatively
9162306a36Sopenharmony_ci * expensive on some Xtensa implementations.
9262306a36Sopenharmony_ci */
9362306a36Sopenharmony_cistatic inline void invalidate_itlb_entry_no_isync (unsigned entry)
9462306a36Sopenharmony_ci{
9562306a36Sopenharmony_ci	/* Caller must follow up with 'isync'. */
9662306a36Sopenharmony_ci	__asm__ __volatile__ ("iitlb  %0\n" : : "a" (entry) );
9762306a36Sopenharmony_ci}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_cistatic inline void invalidate_dtlb_entry_no_isync (unsigned entry)
10062306a36Sopenharmony_ci{
10162306a36Sopenharmony_ci	/* Caller must follow up with 'isync'. */
10262306a36Sopenharmony_ci	__asm__ __volatile__ ("idtlb  %0\n" : : "a" (entry) );
10362306a36Sopenharmony_ci}
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_cistatic inline void set_itlbcfg_register (unsigned long val)
10662306a36Sopenharmony_ci{
10762306a36Sopenharmony_ci	__asm__ __volatile__("wsr  %0, itlbcfg\n\t" "isync\n\t"
10862306a36Sopenharmony_ci			     : : "a" (val));
10962306a36Sopenharmony_ci}
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_cistatic inline void set_dtlbcfg_register (unsigned long val)
11262306a36Sopenharmony_ci{
11362306a36Sopenharmony_ci	__asm__ __volatile__("wsr  %0, dtlbcfg; dsync\n\t"
11462306a36Sopenharmony_ci	    		     : : "a" (val));
11562306a36Sopenharmony_ci}
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_cistatic inline void set_ptevaddr_register (unsigned long val)
11862306a36Sopenharmony_ci{
11962306a36Sopenharmony_ci	__asm__ __volatile__(" wsr  %0, ptevaddr; isync\n"
12062306a36Sopenharmony_ci			     : : "a" (val));
12162306a36Sopenharmony_ci}
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_cistatic inline unsigned long read_ptevaddr_register (void)
12462306a36Sopenharmony_ci{
12562306a36Sopenharmony_ci	unsigned long tmp;
12662306a36Sopenharmony_ci	__asm__ __volatile__("rsr  %0, ptevaddr\n\t" : "=a" (tmp));
12762306a36Sopenharmony_ci	return tmp;
12862306a36Sopenharmony_ci}
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_cistatic inline void write_dtlb_entry (pte_t entry, int way)
13162306a36Sopenharmony_ci{
13262306a36Sopenharmony_ci	__asm__ __volatile__("wdtlb  %1, %0; dsync\n\t"
13362306a36Sopenharmony_ci			     : : "r" (way), "r" (entry) );
13462306a36Sopenharmony_ci}
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_cistatic inline void write_itlb_entry (pte_t entry, int way)
13762306a36Sopenharmony_ci{
13862306a36Sopenharmony_ci	__asm__ __volatile__("witlb  %1, %0; isync\n\t"
13962306a36Sopenharmony_ci	                     : : "r" (way), "r" (entry) );
14062306a36Sopenharmony_ci}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_cistatic inline void invalidate_page_directory (void)
14362306a36Sopenharmony_ci{
14462306a36Sopenharmony_ci	invalidate_dtlb_entry (DTLB_WAY_PGD);
14562306a36Sopenharmony_ci	invalidate_dtlb_entry (DTLB_WAY_PGD+1);
14662306a36Sopenharmony_ci	invalidate_dtlb_entry (DTLB_WAY_PGD+2);
14762306a36Sopenharmony_ci}
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_cistatic inline void invalidate_itlb_mapping (unsigned address)
15062306a36Sopenharmony_ci{
15162306a36Sopenharmony_ci	unsigned long tlb_entry;
15262306a36Sopenharmony_ci	if (((tlb_entry = itlb_probe(address)) & (1 << ITLB_HIT_BIT)) != 0)
15362306a36Sopenharmony_ci		invalidate_itlb_entry(tlb_entry);
15462306a36Sopenharmony_ci}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_cistatic inline void invalidate_dtlb_mapping (unsigned address)
15762306a36Sopenharmony_ci{
15862306a36Sopenharmony_ci	unsigned long tlb_entry;
15962306a36Sopenharmony_ci	if (((tlb_entry = dtlb_probe(address)) & (1 << DTLB_HIT_BIT)) != 0)
16062306a36Sopenharmony_ci		invalidate_dtlb_entry(tlb_entry);
16162306a36Sopenharmony_ci}
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci/*
16462306a36Sopenharmony_ci * DO NOT USE THESE FUNCTIONS.  These instructions aren't part of the Xtensa
16562306a36Sopenharmony_ci * ISA and exist only for test purposes..
16662306a36Sopenharmony_ci * You may find it helpful for MMU debugging, however.
16762306a36Sopenharmony_ci *
16862306a36Sopenharmony_ci * 'at' is the unmodified input register
16962306a36Sopenharmony_ci * 'as' is the output register, as follows (specific to the Linux config):
17062306a36Sopenharmony_ci *
17162306a36Sopenharmony_ci *      as[31..12] contain the virtual address
17262306a36Sopenharmony_ci *      as[11..08] are meaningless
17362306a36Sopenharmony_ci *      as[07..00] contain the asid
17462306a36Sopenharmony_ci */
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_cistatic inline unsigned long read_dtlb_virtual (int way)
17762306a36Sopenharmony_ci{
17862306a36Sopenharmony_ci	unsigned long tmp;
17962306a36Sopenharmony_ci	__asm__ __volatile__("rdtlb0  %0, %1\n\t" : "=a" (tmp), "+a" (way));
18062306a36Sopenharmony_ci	return tmp;
18162306a36Sopenharmony_ci}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_cistatic inline unsigned long read_dtlb_translation (int way)
18462306a36Sopenharmony_ci{
18562306a36Sopenharmony_ci	unsigned long tmp;
18662306a36Sopenharmony_ci	__asm__ __volatile__("rdtlb1  %0, %1\n\t" : "=a" (tmp), "+a" (way));
18762306a36Sopenharmony_ci	return tmp;
18862306a36Sopenharmony_ci}
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_cistatic inline unsigned long read_itlb_virtual (int way)
19162306a36Sopenharmony_ci{
19262306a36Sopenharmony_ci	unsigned long tmp;
19362306a36Sopenharmony_ci	__asm__ __volatile__("ritlb0  %0, %1\n\t" : "=a" (tmp), "+a" (way));
19462306a36Sopenharmony_ci	return tmp;
19562306a36Sopenharmony_ci}
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_cistatic inline unsigned long read_itlb_translation (int way)
19862306a36Sopenharmony_ci{
19962306a36Sopenharmony_ci	unsigned long tmp;
20062306a36Sopenharmony_ci	__asm__ __volatile__("ritlb1  %0, %1\n\t" : "=a" (tmp), "+a" (way));
20162306a36Sopenharmony_ci	return tmp;
20262306a36Sopenharmony_ci}
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci#endif	/* __ASSEMBLY__ */
20562306a36Sopenharmony_ci#endif	/* _XTENSA_TLBFLUSH_H */
206