18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
38c2ecf20Sopenharmony_ci * License.  See the file "COPYING" in the main directory of this archive
48c2ecf20Sopenharmony_ci * for more details.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Copyright (C) 2001 - 2013 Tensilica Inc.
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#ifndef _XTENSA_TLBFLUSH_H
108c2ecf20Sopenharmony_ci#define _XTENSA_TLBFLUSH_H
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <linux/stringify.h>
138c2ecf20Sopenharmony_ci#include <asm/processor.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#define DTLB_WAY_PGD	7
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#define ITLB_ARF_WAYS	4
188c2ecf20Sopenharmony_ci#define DTLB_ARF_WAYS	4
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#define ITLB_HIT_BIT	3
218c2ecf20Sopenharmony_ci#define DTLB_HIT_BIT	4
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#ifndef __ASSEMBLY__
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci/* TLB flushing:
268c2ecf20Sopenharmony_ci *
278c2ecf20Sopenharmony_ci *  - flush_tlb_all() flushes all processes TLB entries
288c2ecf20Sopenharmony_ci *  - flush_tlb_mm(mm) flushes the specified mm context TLB entries
298c2ecf20Sopenharmony_ci *  - flush_tlb_page(mm, vmaddr) flushes a single page
308c2ecf20Sopenharmony_ci *  - flush_tlb_range(mm, start, end) flushes a range of pages
318c2ecf20Sopenharmony_ci */
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_civoid local_flush_tlb_all(void);
348c2ecf20Sopenharmony_civoid local_flush_tlb_mm(struct mm_struct *mm);
358c2ecf20Sopenharmony_civoid local_flush_tlb_page(struct vm_area_struct *vma,
368c2ecf20Sopenharmony_ci		unsigned long page);
378c2ecf20Sopenharmony_civoid local_flush_tlb_range(struct vm_area_struct *vma,
388c2ecf20Sopenharmony_ci		unsigned long start, unsigned long end);
398c2ecf20Sopenharmony_civoid local_flush_tlb_kernel_range(unsigned long start, unsigned long end);
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci#ifdef CONFIG_SMP
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_civoid flush_tlb_all(void);
448c2ecf20Sopenharmony_civoid flush_tlb_mm(struct mm_struct *);
458c2ecf20Sopenharmony_civoid flush_tlb_page(struct vm_area_struct *, unsigned long);
468c2ecf20Sopenharmony_civoid flush_tlb_range(struct vm_area_struct *, unsigned long,
478c2ecf20Sopenharmony_ci		unsigned long);
488c2ecf20Sopenharmony_civoid flush_tlb_kernel_range(unsigned long start, unsigned long end);
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci#else /* !CONFIG_SMP */
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci#define flush_tlb_all()			   local_flush_tlb_all()
538c2ecf20Sopenharmony_ci#define flush_tlb_mm(mm)		   local_flush_tlb_mm(mm)
548c2ecf20Sopenharmony_ci#define flush_tlb_page(vma, page)	   local_flush_tlb_page(vma, page)
558c2ecf20Sopenharmony_ci#define flush_tlb_range(vma, vmaddr, end)  local_flush_tlb_range(vma, vmaddr, \
568c2ecf20Sopenharmony_ci								 end)
578c2ecf20Sopenharmony_ci#define flush_tlb_kernel_range(start, end) local_flush_tlb_kernel_range(start, \
588c2ecf20Sopenharmony_ci									end)
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci#endif /* CONFIG_SMP */
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci/* TLB operations. */
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_cistatic inline unsigned long itlb_probe(unsigned long addr)
658c2ecf20Sopenharmony_ci{
668c2ecf20Sopenharmony_ci	unsigned long tmp;
678c2ecf20Sopenharmony_ci	__asm__ __volatile__("pitlb  %0, %1\n\t" : "=a" (tmp) : "a" (addr));
688c2ecf20Sopenharmony_ci	return tmp;
698c2ecf20Sopenharmony_ci}
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_cistatic inline unsigned long dtlb_probe(unsigned long addr)
728c2ecf20Sopenharmony_ci{
738c2ecf20Sopenharmony_ci	unsigned long tmp;
748c2ecf20Sopenharmony_ci	__asm__ __volatile__("pdtlb  %0, %1\n\t" : "=a" (tmp) : "a" (addr));
758c2ecf20Sopenharmony_ci	return tmp;
768c2ecf20Sopenharmony_ci}
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_cistatic inline void invalidate_itlb_entry (unsigned long probe)
798c2ecf20Sopenharmony_ci{
808c2ecf20Sopenharmony_ci	__asm__ __volatile__("iitlb  %0; isync\n\t" : : "a" (probe));
818c2ecf20Sopenharmony_ci}
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_cistatic inline void invalidate_dtlb_entry (unsigned long probe)
848c2ecf20Sopenharmony_ci{
858c2ecf20Sopenharmony_ci	__asm__ __volatile__("idtlb  %0; dsync\n\t" : : "a" (probe));
868c2ecf20Sopenharmony_ci}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci/* Use the .._no_isync functions with caution.  Generally, these are
898c2ecf20Sopenharmony_ci * handy for bulk invalidates followed by a single 'isync'.  The
908c2ecf20Sopenharmony_ci * caller must follow up with an 'isync', which can be relatively
918c2ecf20Sopenharmony_ci * expensive on some Xtensa implementations.
928c2ecf20Sopenharmony_ci */
938c2ecf20Sopenharmony_cistatic inline void invalidate_itlb_entry_no_isync (unsigned entry)
948c2ecf20Sopenharmony_ci{
958c2ecf20Sopenharmony_ci	/* Caller must follow up with 'isync'. */
968c2ecf20Sopenharmony_ci	__asm__ __volatile__ ("iitlb  %0\n" : : "a" (entry) );
978c2ecf20Sopenharmony_ci}
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_cistatic inline void invalidate_dtlb_entry_no_isync (unsigned entry)
1008c2ecf20Sopenharmony_ci{
1018c2ecf20Sopenharmony_ci	/* Caller must follow up with 'isync'. */
1028c2ecf20Sopenharmony_ci	__asm__ __volatile__ ("idtlb  %0\n" : : "a" (entry) );
1038c2ecf20Sopenharmony_ci}
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_cistatic inline void set_itlbcfg_register (unsigned long val)
1068c2ecf20Sopenharmony_ci{
1078c2ecf20Sopenharmony_ci	__asm__ __volatile__("wsr  %0, itlbcfg\n\t" "isync\n\t"
1088c2ecf20Sopenharmony_ci			     : : "a" (val));
1098c2ecf20Sopenharmony_ci}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_cistatic inline void set_dtlbcfg_register (unsigned long val)
1128c2ecf20Sopenharmony_ci{
1138c2ecf20Sopenharmony_ci	__asm__ __volatile__("wsr  %0, dtlbcfg; dsync\n\t"
1148c2ecf20Sopenharmony_ci	    		     : : "a" (val));
1158c2ecf20Sopenharmony_ci}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_cistatic inline void set_ptevaddr_register (unsigned long val)
1188c2ecf20Sopenharmony_ci{
1198c2ecf20Sopenharmony_ci	__asm__ __volatile__(" wsr  %0, ptevaddr; isync\n"
1208c2ecf20Sopenharmony_ci			     : : "a" (val));
1218c2ecf20Sopenharmony_ci}
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_cistatic inline unsigned long read_ptevaddr_register (void)
1248c2ecf20Sopenharmony_ci{
1258c2ecf20Sopenharmony_ci	unsigned long tmp;
1268c2ecf20Sopenharmony_ci	__asm__ __volatile__("rsr  %0, ptevaddr\n\t" : "=a" (tmp));
1278c2ecf20Sopenharmony_ci	return tmp;
1288c2ecf20Sopenharmony_ci}
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_cistatic inline void write_dtlb_entry (pte_t entry, int way)
1318c2ecf20Sopenharmony_ci{
1328c2ecf20Sopenharmony_ci	__asm__ __volatile__("wdtlb  %1, %0; dsync\n\t"
1338c2ecf20Sopenharmony_ci			     : : "r" (way), "r" (entry) );
1348c2ecf20Sopenharmony_ci}
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_cistatic inline void write_itlb_entry (pte_t entry, int way)
1378c2ecf20Sopenharmony_ci{
1388c2ecf20Sopenharmony_ci	__asm__ __volatile__("witlb  %1, %0; isync\n\t"
1398c2ecf20Sopenharmony_ci	                     : : "r" (way), "r" (entry) );
1408c2ecf20Sopenharmony_ci}
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_cistatic inline void invalidate_page_directory (void)
1438c2ecf20Sopenharmony_ci{
1448c2ecf20Sopenharmony_ci	invalidate_dtlb_entry (DTLB_WAY_PGD);
1458c2ecf20Sopenharmony_ci	invalidate_dtlb_entry (DTLB_WAY_PGD+1);
1468c2ecf20Sopenharmony_ci	invalidate_dtlb_entry (DTLB_WAY_PGD+2);
1478c2ecf20Sopenharmony_ci}
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_cistatic inline void invalidate_itlb_mapping (unsigned address)
1508c2ecf20Sopenharmony_ci{
1518c2ecf20Sopenharmony_ci	unsigned long tlb_entry;
1528c2ecf20Sopenharmony_ci	if (((tlb_entry = itlb_probe(address)) & (1 << ITLB_HIT_BIT)) != 0)
1538c2ecf20Sopenharmony_ci		invalidate_itlb_entry(tlb_entry);
1548c2ecf20Sopenharmony_ci}
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_cistatic inline void invalidate_dtlb_mapping (unsigned address)
1578c2ecf20Sopenharmony_ci{
1588c2ecf20Sopenharmony_ci	unsigned long tlb_entry;
1598c2ecf20Sopenharmony_ci	if (((tlb_entry = dtlb_probe(address)) & (1 << DTLB_HIT_BIT)) != 0)
1608c2ecf20Sopenharmony_ci		invalidate_dtlb_entry(tlb_entry);
1618c2ecf20Sopenharmony_ci}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci/*
1648c2ecf20Sopenharmony_ci * DO NOT USE THESE FUNCTIONS.  These instructions aren't part of the Xtensa
1658c2ecf20Sopenharmony_ci * ISA and exist only for test purposes..
1668c2ecf20Sopenharmony_ci * You may find it helpful for MMU debugging, however.
1678c2ecf20Sopenharmony_ci *
1688c2ecf20Sopenharmony_ci * 'at' is the unmodified input register
1698c2ecf20Sopenharmony_ci * 'as' is the output register, as follows (specific to the Linux config):
1708c2ecf20Sopenharmony_ci *
1718c2ecf20Sopenharmony_ci *      as[31..12] contain the virtual address
1728c2ecf20Sopenharmony_ci *      as[11..08] are meaningless
1738c2ecf20Sopenharmony_ci *      as[07..00] contain the asid
1748c2ecf20Sopenharmony_ci */
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_cistatic inline unsigned long read_dtlb_virtual (int way)
1778c2ecf20Sopenharmony_ci{
1788c2ecf20Sopenharmony_ci	unsigned long tmp;
1798c2ecf20Sopenharmony_ci	__asm__ __volatile__("rdtlb0  %0, %1\n\t" : "=a" (tmp), "+a" (way));
1808c2ecf20Sopenharmony_ci	return tmp;
1818c2ecf20Sopenharmony_ci}
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_cistatic inline unsigned long read_dtlb_translation (int way)
1848c2ecf20Sopenharmony_ci{
1858c2ecf20Sopenharmony_ci	unsigned long tmp;
1868c2ecf20Sopenharmony_ci	__asm__ __volatile__("rdtlb1  %0, %1\n\t" : "=a" (tmp), "+a" (way));
1878c2ecf20Sopenharmony_ci	return tmp;
1888c2ecf20Sopenharmony_ci}
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_cistatic inline unsigned long read_itlb_virtual (int way)
1918c2ecf20Sopenharmony_ci{
1928c2ecf20Sopenharmony_ci	unsigned long tmp;
1938c2ecf20Sopenharmony_ci	__asm__ __volatile__("ritlb0  %0, %1\n\t" : "=a" (tmp), "+a" (way));
1948c2ecf20Sopenharmony_ci	return tmp;
1958c2ecf20Sopenharmony_ci}
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_cistatic inline unsigned long read_itlb_translation (int way)
1988c2ecf20Sopenharmony_ci{
1998c2ecf20Sopenharmony_ci	unsigned long tmp;
2008c2ecf20Sopenharmony_ci	__asm__ __volatile__("ritlb1  %0, %1\n\t" : "=a" (tmp), "+a" (way));
2018c2ecf20Sopenharmony_ci	return tmp;
2028c2ecf20Sopenharmony_ci}
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci#endif	/* __ASSEMBLY__ */
2058c2ecf20Sopenharmony_ci#endif	/* _XTENSA_TLBFLUSH_H */
206