linux/arch/arm/kernel/smp_tlb.c
<<
>>
Prefs
   1/*
   2 *  linux/arch/arm/kernel/smp_tlb.c
   3 *
   4 *  Copyright (C) 2002 ARM Limited, All Rights Reserved.
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 as
   8 * published by the Free Software Foundation.
   9 */
  10#include <linux/preempt.h>
  11#include <linux/smp.h>
  12
  13#include <asm/smp_plat.h>
  14#include <asm/tlbflush.h>
  15#include <asm/mmu_context.h>
  16
  17/**********************************************************************/
  18
  19/*
  20 * TLB operations
  21 */
  22struct tlb_args {
  23        struct vm_area_struct *ta_vma;
  24        unsigned long ta_start;
  25        unsigned long ta_end;
  26};
  27
  28static inline void ipi_flush_tlb_all(void *ignored)
  29{
  30        local_flush_tlb_all();
  31}
  32
  33static inline void ipi_flush_tlb_mm(void *arg)
  34{
  35        struct mm_struct *mm = (struct mm_struct *)arg;
  36
  37        local_flush_tlb_mm(mm);
  38}
  39
  40static inline void ipi_flush_tlb_page(void *arg)
  41{
  42        struct tlb_args *ta = (struct tlb_args *)arg;
  43
  44        local_flush_tlb_page(ta->ta_vma, ta->ta_start);
  45}
  46
  47static inline void ipi_flush_tlb_kernel_page(void *arg)
  48{
  49        struct tlb_args *ta = (struct tlb_args *)arg;
  50
  51        local_flush_tlb_kernel_page(ta->ta_start);
  52}
  53
  54static inline void ipi_flush_tlb_range(void *arg)
  55{
  56        struct tlb_args *ta = (struct tlb_args *)arg;
  57
  58        local_flush_tlb_range(ta->ta_vma, ta->ta_start, ta->ta_end);
  59}
  60
  61static inline void ipi_flush_tlb_kernel_range(void *arg)
  62{
  63        struct tlb_args *ta = (struct tlb_args *)arg;
  64
  65        local_flush_tlb_kernel_range(ta->ta_start, ta->ta_end);
  66}
  67
  68static inline void ipi_flush_bp_all(void *ignored)
  69{
  70        local_flush_bp_all();
  71}
  72
  73#ifdef CONFIG_ARM_ERRATA_798181
  74bool (*erratum_a15_798181_handler)(void);
  75
  76static bool erratum_a15_798181_partial(void)
  77{
  78        asm("mcr p15, 0, %0, c8, c3, 1" : : "r" (0));
  79        dsb(ish);
  80        return false;
  81}
  82
  83static bool erratum_a15_798181_broadcast(void)
  84{
  85        asm("mcr p15, 0, %0, c8, c3, 1" : : "r" (0));
  86        dsb(ish);
  87        return true;
  88}
  89
  90void erratum_a15_798181_init(void)
  91{
  92        unsigned int midr = read_cpuid_id();
  93        unsigned int revidr = read_cpuid(CPUID_REVIDR);
  94
  95        /* Brahma-B15 r0p0..r0p2 affected
  96         * Cortex-A15 r0p0..r3p2 w/o ECO fix affected */
  97        if ((midr & 0xff0ffff0) == 0x420f00f0 && midr <= 0x420f00f2)
  98                erratum_a15_798181_handler = erratum_a15_798181_broadcast;
  99        else if ((midr & 0xff0ffff0) == 0x410fc0f0 && midr <= 0x413fc0f2 &&
 100                 (revidr & 0x210) != 0x210) {
 101                if (revidr & 0x10)
 102                        erratum_a15_798181_handler =
 103                                erratum_a15_798181_partial;
 104                else
 105                        erratum_a15_798181_handler =
 106                                erratum_a15_798181_broadcast;
 107        }
 108}
 109#endif
 110
 111static void ipi_flush_tlb_a15_erratum(void *arg)
 112{
 113        dmb();
 114}
 115
 116static void broadcast_tlb_a15_erratum(void)
 117{
 118        if (!erratum_a15_798181())
 119                return;
 120
 121        smp_call_function(ipi_flush_tlb_a15_erratum, NULL, 1);
 122}
 123
 124static void broadcast_tlb_mm_a15_erratum(struct mm_struct *mm)
 125{
 126        int this_cpu;
 127        cpumask_t mask = { CPU_BITS_NONE };
 128
 129        if (!erratum_a15_798181())
 130                return;
 131
 132        this_cpu = get_cpu();
 133        a15_erratum_get_cpumask(this_cpu, mm, &mask);
 134        smp_call_function_many(&mask, ipi_flush_tlb_a15_erratum, NULL, 1);
 135        put_cpu();
 136}
 137
 138void flush_tlb_all(void)
 139{
 140        if (tlb_ops_need_broadcast())
 141                on_each_cpu(ipi_flush_tlb_all, NULL, 1);
 142        else
 143                __flush_tlb_all();
 144        broadcast_tlb_a15_erratum();
 145}
 146
 147void flush_tlb_mm(struct mm_struct *mm)
 148{
 149        if (tlb_ops_need_broadcast())
 150                on_each_cpu_mask(mm_cpumask(mm), ipi_flush_tlb_mm, mm, 1);
 151        else
 152                __flush_tlb_mm(mm);
 153        broadcast_tlb_mm_a15_erratum(mm);
 154}
 155
 156void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
 157{
 158        if (tlb_ops_need_broadcast()) {
 159                struct tlb_args ta;
 160                ta.ta_vma = vma;
 161                ta.ta_start = uaddr;
 162                on_each_cpu_mask(mm_cpumask(vma->vm_mm), ipi_flush_tlb_page,
 163                                        &ta, 1);
 164        } else
 165                __flush_tlb_page(vma, uaddr);
 166        broadcast_tlb_mm_a15_erratum(vma->vm_mm);
 167}
 168
 169void flush_tlb_kernel_page(unsigned long kaddr)
 170{
 171        if (tlb_ops_need_broadcast()) {
 172                struct tlb_args ta;
 173                ta.ta_start = kaddr;
 174                on_each_cpu(ipi_flush_tlb_kernel_page, &ta, 1);
 175        } else
 176                __flush_tlb_kernel_page(kaddr);
 177        broadcast_tlb_a15_erratum();
 178}
 179
 180void flush_tlb_range(struct vm_area_struct *vma,
 181                     unsigned long start, unsigned long end)
 182{
 183        if (tlb_ops_need_broadcast()) {
 184                struct tlb_args ta;
 185                ta.ta_vma = vma;
 186                ta.ta_start = start;
 187                ta.ta_end = end;
 188                on_each_cpu_mask(mm_cpumask(vma->vm_mm), ipi_flush_tlb_range,
 189                                        &ta, 1);
 190        } else
 191                local_flush_tlb_range(vma, start, end);
 192        broadcast_tlb_mm_a15_erratum(vma->vm_mm);
 193}
 194
 195void flush_tlb_kernel_range(unsigned long start, unsigned long end)
 196{
 197        if (tlb_ops_need_broadcast()) {
 198                struct tlb_args ta;
 199                ta.ta_start = start;
 200                ta.ta_end = end;
 201                on_each_cpu(ipi_flush_tlb_kernel_range, &ta, 1);
 202        } else
 203                local_flush_tlb_kernel_range(start, end);
 204        broadcast_tlb_a15_erratum();
 205}
 206
 207void flush_bp_all(void)
 208{
 209        if (tlb_ops_need_broadcast())
 210                on_each_cpu(ipi_flush_bp_all, NULL, 1);
 211        else
 212                __flush_bp_all();
 213}
 214