linux/arch/csky/mm/tlb.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
   3
   4#include <linux/init.h>
   5#include <linux/mm.h>
   6#include <linux/module.h>
   7#include <linux/sched.h>
   8
   9#include <asm/mmu_context.h>
  10#include <asm/setup.h>
  11
  12/*
  13 * One C-SKY MMU TLB entry contain two PFN/page entry, ie:
  14 * 1VPN -> 2PFN
  15 */
  16#define TLB_ENTRY_SIZE          (PAGE_SIZE * 2)
  17#define TLB_ENTRY_SIZE_MASK     (PAGE_MASK << 1)
  18
  19void flush_tlb_all(void)
  20{
  21        tlb_invalid_all();
  22}
  23
  24void flush_tlb_mm(struct mm_struct *mm)
  25{
  26#ifdef CONFIG_CPU_HAS_TLBI
  27        asm volatile("tlbi.asids %0"::"r"(cpu_asid(mm)));
  28#else
  29        tlb_invalid_all();
  30#endif
  31}
  32
  33/*
  34 * MMU operation regs only could invalid tlb entry in jtlb and we
  35 * need change asid field to invalid I-utlb & D-utlb.
  36 */
  37#ifndef CONFIG_CPU_HAS_TLBI
  38#define restore_asid_inv_utlb(oldpid, newpid) \
  39do { \
  40        if (oldpid == newpid) \
  41                write_mmu_entryhi(oldpid + 1); \
  42        write_mmu_entryhi(oldpid); \
  43} while (0)
  44#endif
  45
  46void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
  47                        unsigned long end)
  48{
  49        unsigned long newpid = cpu_asid(vma->vm_mm);
  50
  51        start &= TLB_ENTRY_SIZE_MASK;
  52        end   += TLB_ENTRY_SIZE - 1;
  53        end   &= TLB_ENTRY_SIZE_MASK;
  54
  55#ifdef CONFIG_CPU_HAS_TLBI
  56        while (start < end) {
  57                asm volatile("tlbi.vas %0"::"r"(start | newpid));
  58                start += 2*PAGE_SIZE;
  59        }
  60        sync_is();
  61#else
  62        {
  63        unsigned long flags, oldpid;
  64
  65        local_irq_save(flags);
  66        oldpid = read_mmu_entryhi() & ASID_MASK;
  67        while (start < end) {
  68                int idx;
  69
  70                write_mmu_entryhi(start | newpid);
  71                start += 2*PAGE_SIZE;
  72                tlb_probe();
  73                idx = read_mmu_index();
  74                if (idx >= 0)
  75                        tlb_invalid_indexed();
  76        }
  77        restore_asid_inv_utlb(oldpid, newpid);
  78        local_irq_restore(flags);
  79        }
  80#endif
  81}
  82
  83void flush_tlb_kernel_range(unsigned long start, unsigned long end)
  84{
  85        start &= TLB_ENTRY_SIZE_MASK;
  86        end   += TLB_ENTRY_SIZE - 1;
  87        end   &= TLB_ENTRY_SIZE_MASK;
  88
  89#ifdef CONFIG_CPU_HAS_TLBI
  90        while (start < end) {
  91                asm volatile("tlbi.vaas %0"::"r"(start));
  92                start += 2*PAGE_SIZE;
  93        }
  94        sync_is();
  95#else
  96        {
  97        unsigned long flags, oldpid;
  98
  99        local_irq_save(flags);
 100        oldpid = read_mmu_entryhi() & ASID_MASK;
 101        while (start < end) {
 102                int idx;
 103
 104                write_mmu_entryhi(start | oldpid);
 105                start += 2*PAGE_SIZE;
 106                tlb_probe();
 107                idx = read_mmu_index();
 108                if (idx >= 0)
 109                        tlb_invalid_indexed();
 110        }
 111        restore_asid_inv_utlb(oldpid, oldpid);
 112        local_irq_restore(flags);
 113        }
 114#endif
 115}
 116
 117void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
 118{
 119        int newpid = cpu_asid(vma->vm_mm);
 120
 121        addr &= TLB_ENTRY_SIZE_MASK;
 122
 123#ifdef CONFIG_CPU_HAS_TLBI
 124        asm volatile("tlbi.vas %0"::"r"(addr | newpid));
 125        sync_is();
 126#else
 127        {
 128        int oldpid, idx;
 129        unsigned long flags;
 130
 131        local_irq_save(flags);
 132        oldpid = read_mmu_entryhi() & ASID_MASK;
 133        write_mmu_entryhi(addr | newpid);
 134        tlb_probe();
 135        idx = read_mmu_index();
 136        if (idx >= 0)
 137                tlb_invalid_indexed();
 138
 139        restore_asid_inv_utlb(oldpid, newpid);
 140        local_irq_restore(flags);
 141        }
 142#endif
 143}
 144
 145void flush_tlb_one(unsigned long addr)
 146{
 147        addr &= TLB_ENTRY_SIZE_MASK;
 148
 149#ifdef CONFIG_CPU_HAS_TLBI
 150        asm volatile("tlbi.vaas %0"::"r"(addr));
 151        sync_is();
 152#else
 153        {
 154        int oldpid, idx;
 155        unsigned long flags;
 156
 157        local_irq_save(flags);
 158        oldpid = read_mmu_entryhi() & ASID_MASK;
 159        write_mmu_entryhi(addr | oldpid);
 160        tlb_probe();
 161        idx = read_mmu_index();
 162        if (idx >= 0)
 163                tlb_invalid_indexed();
 164
 165        restore_asid_inv_utlb(oldpid, oldpid);
 166        local_irq_restore(flags);
 167        }
 168#endif
 169}
 170EXPORT_SYMBOL(flush_tlb_one);
 171