162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci#ifndef _M68K_TLBFLUSH_H
362306a36Sopenharmony_ci#define _M68K_TLBFLUSH_H
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#ifdef CONFIG_MMU
662306a36Sopenharmony_ci#ifndef CONFIG_SUN3
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <asm/current.h>
962306a36Sopenharmony_ci#include <asm/mcfmmu.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_cistatic inline void flush_tlb_kernel_page(void *addr)
1262306a36Sopenharmony_ci{
1362306a36Sopenharmony_ci	if (CPU_IS_COLDFIRE) {
1462306a36Sopenharmony_ci		mmu_write(MMUOR, MMUOR_CNL);
1562306a36Sopenharmony_ci	} else if (CPU_IS_040_OR_060) {
1662306a36Sopenharmony_ci		set_fc(SUPER_DATA);
1762306a36Sopenharmony_ci		__asm__ __volatile__(".chip 68040\n\t"
1862306a36Sopenharmony_ci				     "pflush (%0)\n\t"
1962306a36Sopenharmony_ci				     ".chip 68k"
2062306a36Sopenharmony_ci				     : : "a" (addr));
2162306a36Sopenharmony_ci		set_fc(USER_DATA);
2262306a36Sopenharmony_ci	} else if (CPU_IS_020_OR_030)
2362306a36Sopenharmony_ci		__asm__ __volatile__("pflush #4,#4,(%0)" : : "a" (addr));
2462306a36Sopenharmony_ci}
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci/*
2762306a36Sopenharmony_ci * flush all user-space atc entries.
2862306a36Sopenharmony_ci */
2962306a36Sopenharmony_cistatic inline void __flush_tlb(void)
3062306a36Sopenharmony_ci{
3162306a36Sopenharmony_ci	if (CPU_IS_COLDFIRE) {
3262306a36Sopenharmony_ci		mmu_write(MMUOR, MMUOR_CNL);
3362306a36Sopenharmony_ci	} else if (CPU_IS_040_OR_060) {
3462306a36Sopenharmony_ci		__asm__ __volatile__(".chip 68040\n\t"
3562306a36Sopenharmony_ci				     "pflushan\n\t"
3662306a36Sopenharmony_ci				     ".chip 68k");
3762306a36Sopenharmony_ci	} else if (CPU_IS_020_OR_030) {
3862306a36Sopenharmony_ci		__asm__ __volatile__("pflush #0,#4");
3962306a36Sopenharmony_ci	}
4062306a36Sopenharmony_ci}
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cistatic inline void __flush_tlb040_one(unsigned long addr)
4362306a36Sopenharmony_ci{
4462306a36Sopenharmony_ci	__asm__ __volatile__(".chip 68040\n\t"
4562306a36Sopenharmony_ci			     "pflush (%0)\n\t"
4662306a36Sopenharmony_ci			     ".chip 68k"
4762306a36Sopenharmony_ci			     : : "a" (addr));
4862306a36Sopenharmony_ci}
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_cistatic inline void __flush_tlb_one(unsigned long addr)
5162306a36Sopenharmony_ci{
5262306a36Sopenharmony_ci	if (CPU_IS_COLDFIRE)
5362306a36Sopenharmony_ci		mmu_write(MMUOR, MMUOR_CNL);
5462306a36Sopenharmony_ci	else if (CPU_IS_040_OR_060)
5562306a36Sopenharmony_ci		__flush_tlb040_one(addr);
5662306a36Sopenharmony_ci	else if (CPU_IS_020_OR_030)
5762306a36Sopenharmony_ci		__asm__ __volatile__("pflush #0,#4,(%0)" : : "a" (addr));
5862306a36Sopenharmony_ci}
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci#define flush_tlb() __flush_tlb()
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci/*
6362306a36Sopenharmony_ci * flush all atc entries (both kernel and user-space entries).
6462306a36Sopenharmony_ci */
6562306a36Sopenharmony_cistatic inline void flush_tlb_all(void)
6662306a36Sopenharmony_ci{
6762306a36Sopenharmony_ci	if (CPU_IS_COLDFIRE) {
6862306a36Sopenharmony_ci		mmu_write(MMUOR, MMUOR_CNL);
6962306a36Sopenharmony_ci	} else if (CPU_IS_040_OR_060) {
7062306a36Sopenharmony_ci		__asm__ __volatile__(".chip 68040\n\t"
7162306a36Sopenharmony_ci				     "pflusha\n\t"
7262306a36Sopenharmony_ci				     ".chip 68k");
7362306a36Sopenharmony_ci	} else if (CPU_IS_020_OR_030) {
7462306a36Sopenharmony_ci		__asm__ __volatile__("pflusha");
7562306a36Sopenharmony_ci	}
7662306a36Sopenharmony_ci}
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cistatic inline void flush_tlb_mm(struct mm_struct *mm)
7962306a36Sopenharmony_ci{
8062306a36Sopenharmony_ci	if (mm == current->active_mm)
8162306a36Sopenharmony_ci		__flush_tlb();
8262306a36Sopenharmony_ci}
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_cistatic inline void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
8562306a36Sopenharmony_ci{
8662306a36Sopenharmony_ci	if (vma->vm_mm == current->active_mm)
8762306a36Sopenharmony_ci		__flush_tlb_one(addr);
8862306a36Sopenharmony_ci}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_cistatic inline void flush_tlb_range(struct vm_area_struct *vma,
9162306a36Sopenharmony_ci				   unsigned long start, unsigned long end)
9262306a36Sopenharmony_ci{
9362306a36Sopenharmony_ci	if (vma->vm_mm == current->active_mm)
9462306a36Sopenharmony_ci		__flush_tlb();
9562306a36Sopenharmony_ci}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_cistatic inline void flush_tlb_kernel_range(unsigned long start, unsigned long end)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci	flush_tlb_all();
10062306a36Sopenharmony_ci}
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci#else
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci/* Reserved PMEGs. */
10662306a36Sopenharmony_ciextern char sun3_reserved_pmeg[SUN3_PMEGS_NUM];
10762306a36Sopenharmony_ciextern unsigned long pmeg_vaddr[SUN3_PMEGS_NUM];
10862306a36Sopenharmony_ciextern unsigned char pmeg_alloc[SUN3_PMEGS_NUM];
10962306a36Sopenharmony_ciextern unsigned char pmeg_ctx[SUN3_PMEGS_NUM];
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci/* Flush all userspace mappings one by one...  (why no flush command,
11262306a36Sopenharmony_ci   sun?) */
11362306a36Sopenharmony_cistatic inline void flush_tlb_all(void)
11462306a36Sopenharmony_ci{
11562306a36Sopenharmony_ci       unsigned long addr;
11662306a36Sopenharmony_ci       unsigned char ctx, oldctx;
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci       oldctx = sun3_get_context();
11962306a36Sopenharmony_ci       for(addr = 0x00000000; addr < TASK_SIZE; addr += SUN3_PMEG_SIZE) {
12062306a36Sopenharmony_ci	       for(ctx = 0; ctx < 8; ctx++) {
12162306a36Sopenharmony_ci		       sun3_put_context(ctx);
12262306a36Sopenharmony_ci		       sun3_put_segmap(addr, SUN3_INVALID_PMEG);
12362306a36Sopenharmony_ci	       }
12462306a36Sopenharmony_ci       }
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci       sun3_put_context(oldctx);
12762306a36Sopenharmony_ci       /* erase all of the userspace pmeg maps, we've clobbered them
12862306a36Sopenharmony_ci	  all anyway */
12962306a36Sopenharmony_ci       for(addr = 0; addr < SUN3_INVALID_PMEG; addr++) {
13062306a36Sopenharmony_ci	       if(pmeg_alloc[addr] == 1) {
13162306a36Sopenharmony_ci		       pmeg_alloc[addr] = 0;
13262306a36Sopenharmony_ci		       pmeg_ctx[addr] = 0;
13362306a36Sopenharmony_ci		       pmeg_vaddr[addr] = 0;
13462306a36Sopenharmony_ci	       }
13562306a36Sopenharmony_ci       }
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci}
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci/* Clear user TLB entries within the context named in mm */
14062306a36Sopenharmony_cistatic inline void flush_tlb_mm (struct mm_struct *mm)
14162306a36Sopenharmony_ci{
14262306a36Sopenharmony_ci     unsigned char oldctx;
14362306a36Sopenharmony_ci     unsigned char seg;
14462306a36Sopenharmony_ci     unsigned long i;
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci     oldctx = sun3_get_context();
14762306a36Sopenharmony_ci     sun3_put_context(mm->context);
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci     for(i = 0; i < TASK_SIZE; i += SUN3_PMEG_SIZE) {
15062306a36Sopenharmony_ci	     seg = sun3_get_segmap(i);
15162306a36Sopenharmony_ci	     if(seg == SUN3_INVALID_PMEG)
15262306a36Sopenharmony_ci		     continue;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	     sun3_put_segmap(i, SUN3_INVALID_PMEG);
15562306a36Sopenharmony_ci	     pmeg_alloc[seg] = 0;
15662306a36Sopenharmony_ci	     pmeg_ctx[seg] = 0;
15762306a36Sopenharmony_ci	     pmeg_vaddr[seg] = 0;
15862306a36Sopenharmony_ci     }
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci     sun3_put_context(oldctx);
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci}
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci/* Flush a single TLB page. In this case, we're limited to flushing a
16562306a36Sopenharmony_ci   single PMEG */
16662306a36Sopenharmony_cistatic inline void flush_tlb_page (struct vm_area_struct *vma,
16762306a36Sopenharmony_ci				   unsigned long addr)
16862306a36Sopenharmony_ci{
16962306a36Sopenharmony_ci	unsigned char oldctx;
17062306a36Sopenharmony_ci	unsigned char i;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	oldctx = sun3_get_context();
17362306a36Sopenharmony_ci	sun3_put_context(vma->vm_mm->context);
17462306a36Sopenharmony_ci	addr &= ~SUN3_PMEG_MASK;
17562306a36Sopenharmony_ci	if((i = sun3_get_segmap(addr)) != SUN3_INVALID_PMEG)
17662306a36Sopenharmony_ci	{
17762306a36Sopenharmony_ci		pmeg_alloc[i] = 0;
17862306a36Sopenharmony_ci		pmeg_ctx[i] = 0;
17962306a36Sopenharmony_ci		pmeg_vaddr[i] = 0;
18062306a36Sopenharmony_ci		sun3_put_segmap (addr,  SUN3_INVALID_PMEG);
18162306a36Sopenharmony_ci	}
18262306a36Sopenharmony_ci	sun3_put_context(oldctx);
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci}
18562306a36Sopenharmony_ci/* Flush a range of pages from TLB. */
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_cistatic inline void flush_tlb_range (struct vm_area_struct *vma,
18862306a36Sopenharmony_ci		      unsigned long start, unsigned long end)
18962306a36Sopenharmony_ci{
19062306a36Sopenharmony_ci	struct mm_struct *mm = vma->vm_mm;
19162306a36Sopenharmony_ci	unsigned char seg, oldctx;
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	start &= ~SUN3_PMEG_MASK;
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	oldctx = sun3_get_context();
19662306a36Sopenharmony_ci	sun3_put_context(mm->context);
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	while(start < end)
19962306a36Sopenharmony_ci	{
20062306a36Sopenharmony_ci		if((seg = sun3_get_segmap(start)) == SUN3_INVALID_PMEG)
20162306a36Sopenharmony_ci		     goto next;
20262306a36Sopenharmony_ci		if(pmeg_ctx[seg] == mm->context) {
20362306a36Sopenharmony_ci			pmeg_alloc[seg] = 0;
20462306a36Sopenharmony_ci			pmeg_ctx[seg] = 0;
20562306a36Sopenharmony_ci			pmeg_vaddr[seg] = 0;
20662306a36Sopenharmony_ci		}
20762306a36Sopenharmony_ci		sun3_put_segmap(start, SUN3_INVALID_PMEG);
20862306a36Sopenharmony_ci	next:
20962306a36Sopenharmony_ci		start += SUN3_PMEG_SIZE;
21062306a36Sopenharmony_ci	}
21162306a36Sopenharmony_ci}
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_cistatic inline void flush_tlb_kernel_range(unsigned long start, unsigned long end)
21462306a36Sopenharmony_ci{
21562306a36Sopenharmony_ci	flush_tlb_all();
21662306a36Sopenharmony_ci}
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci/* Flush kernel page from TLB. */
21962306a36Sopenharmony_cistatic inline void flush_tlb_kernel_page (unsigned long addr)
22062306a36Sopenharmony_ci{
22162306a36Sopenharmony_ci	sun3_put_segmap (addr & ~(SUN3_PMEG_SIZE - 1), SUN3_INVALID_PMEG);
22262306a36Sopenharmony_ci}
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci#endif
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci#else /* !CONFIG_MMU */
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci/*
22962306a36Sopenharmony_ci * flush all user-space atc entries.
23062306a36Sopenharmony_ci */
23162306a36Sopenharmony_cistatic inline void __flush_tlb(void)
23262306a36Sopenharmony_ci{
23362306a36Sopenharmony_ci	BUG();
23462306a36Sopenharmony_ci}
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_cistatic inline void __flush_tlb_one(unsigned long addr)
23762306a36Sopenharmony_ci{
23862306a36Sopenharmony_ci	BUG();
23962306a36Sopenharmony_ci}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci#define flush_tlb() __flush_tlb()
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci/*
24462306a36Sopenharmony_ci * flush all atc entries (both kernel and user-space entries).
24562306a36Sopenharmony_ci */
24662306a36Sopenharmony_cistatic inline void flush_tlb_all(void)
24762306a36Sopenharmony_ci{
24862306a36Sopenharmony_ci	BUG();
24962306a36Sopenharmony_ci}
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_cistatic inline void flush_tlb_mm(struct mm_struct *mm)
25262306a36Sopenharmony_ci{
25362306a36Sopenharmony_ci	BUG();
25462306a36Sopenharmony_ci}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_cistatic inline void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
25762306a36Sopenharmony_ci{
25862306a36Sopenharmony_ci	BUG();
25962306a36Sopenharmony_ci}
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_cistatic inline void flush_tlb_range(struct vm_area_struct *vma,
26262306a36Sopenharmony_ci				   unsigned long start, unsigned long end)
26362306a36Sopenharmony_ci{
26462306a36Sopenharmony_ci	BUG();
26562306a36Sopenharmony_ci}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_cistatic inline void flush_tlb_kernel_page(unsigned long addr)
26862306a36Sopenharmony_ci{
26962306a36Sopenharmony_ci	BUG();
27062306a36Sopenharmony_ci}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci#endif /* CONFIG_MMU */
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci#endif /* _M68K_TLBFLUSH_H */
275