linux/arch/hexagon/mm/cache.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Cache management functions for Hexagon
   4 *
   5 * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
   6 */
   7
   8#include <linux/mm.h>
   9#include <asm/cacheflush.h>
  10#include <asm/hexagon_vm.h>
  11
  12#define spanlines(start, end) \
  13        (((end - (start & ~(LINESIZE - 1))) >> LINEBITS) + 1)
  14
  15void flush_dcache_range(unsigned long start, unsigned long end)
  16{
  17        unsigned long lines = spanlines(start, end-1);
  18        unsigned long i, flags;
  19
  20        start &= ~(LINESIZE - 1);
  21
  22        local_irq_save(flags);
  23
  24        for (i = 0; i < lines; i++) {
  25                __asm__ __volatile__ (
  26                "       dccleaninva(%0);        "
  27                :
  28                : "r" (start)
  29                );
  30                start += LINESIZE;
  31        }
  32        local_irq_restore(flags);
  33}
  34
  35void flush_icache_range(unsigned long start, unsigned long end)
  36{
  37        unsigned long lines = spanlines(start, end-1);
  38        unsigned long i, flags;
  39
  40        start &= ~(LINESIZE - 1);
  41
  42        local_irq_save(flags);
  43
  44        for (i = 0; i < lines; i++) {
  45                __asm__ __volatile__ (
  46                        "       dccleana(%0); "
  47                        "       icinva(%0);     "
  48                        :
  49                        : "r" (start)
  50                );
  51                start += LINESIZE;
  52        }
  53        __asm__ __volatile__ (
  54                "isync"
  55        );
  56        local_irq_restore(flags);
  57}
  58EXPORT_SYMBOL(flush_icache_range);
  59
  60void hexagon_clean_dcache_range(unsigned long start, unsigned long end)
  61{
  62        unsigned long lines = spanlines(start, end-1);
  63        unsigned long i, flags;
  64
  65        start &= ~(LINESIZE - 1);
  66
  67        local_irq_save(flags);
  68
  69        for (i = 0; i < lines; i++) {
  70                __asm__ __volatile__ (
  71                "       dccleana(%0);   "
  72                :
  73                : "r" (start)
  74                );
  75                start += LINESIZE;
  76        }
  77        local_irq_restore(flags);
  78}
  79
  80void hexagon_inv_dcache_range(unsigned long start, unsigned long end)
  81{
  82        unsigned long lines = spanlines(start, end-1);
  83        unsigned long i, flags;
  84
  85        start &= ~(LINESIZE - 1);
  86
  87        local_irq_save(flags);
  88
  89        for (i = 0; i < lines; i++) {
  90                __asm__ __volatile__ (
  91                "       dcinva(%0);     "
  92                :
  93                : "r" (start)
  94                );
  95                start += LINESIZE;
  96        }
  97        local_irq_restore(flags);
  98}
  99
 100
 101
 102
 103/*
 104 * This is just really brutal and shouldn't be used anyways,
 105 * especially on V2.  Left here just in case.
 106 */
 107void flush_cache_all_hexagon(void)
 108{
 109        unsigned long flags;
 110        local_irq_save(flags);
 111        __vmcache_ickill();
 112        __vmcache_dckill();
 113        __vmcache_l2kill();
 114        local_irq_restore(flags);
 115        mb();
 116}
 117
 118void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
 119                       unsigned long vaddr, void *dst, void *src, int len)
 120{
 121        memcpy(dst, src, len);
 122        if (vma->vm_flags & VM_EXEC) {
 123                flush_icache_range((unsigned long) dst,
 124                (unsigned long) dst + len);
 125        }
 126}
 127