The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/arch/score/mm/cache.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * arch/score/mm/cache.c
    3  *
    4  * Score Processor version.
    5  *
    6  * Copyright (C) 2009 Sunplus Core Technology Co., Ltd.
    7  *  Lennox Wu <lennox.wu@sunplusct.com>
    8  *  Chen Liqin <liqin.chen@sunplusct.com>
    9  *
   10  * This program is free software; you can redistribute it and/or modify
   11  * it under the terms of the GNU General Public License as published by
   12  * the Free Software Foundation; either version 2 of the License, or
   13  * (at your option) any later version.
   14  *
   15  * This program is distributed in the hope that it will be useful,
   16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   18  * GNU General Public License for more details.
   19  *
   20  * You should have received a copy of the GNU General Public License
   21  * along with this program; if not, see the file COPYING, or write
   22  * to the Free Software Foundation, Inc.,
   23  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
   24  */
   25 
   26 #include <linux/init.h>
   27 #include <linux/linkage.h>
   28 #include <linux/kernel.h>
   29 #include <linux/mm.h>
   30 #include <linux/module.h>
   31 #include <linux/sched.h>
   32 #include <linux/fs.h>
   33 
   34 #include <asm/mmu_context.h>
   35 
   36 /*
   37 Just flush entire Dcache!!
   38 You must ensure the page doesn't include instructions, because
   39 the function will not flush the Icache.
   40 The addr must be cache aligned.
   41 */
   42 static void flush_data_cache_page(unsigned long addr)
   43 {
   44         unsigned int i;
   45         for (i = 0; i < (PAGE_SIZE / L1_CACHE_BYTES); i += L1_CACHE_BYTES) {
   46                 __asm__ __volatile__(
   47                 "cache 0x0e, [%0, 0]\n"
   48                 "cache 0x1a, [%0, 0]\n"
   49                 "nop\n"
   50                 : : "r" (addr));
   51                 addr += L1_CACHE_BYTES;
   52         }
   53 }
   54 
   55 void flush_dcache_page(struct page *page)
   56 {
   57         struct address_space *mapping = page_mapping(page);
   58         unsigned long addr;
   59 
   60         if (PageHighMem(page))
   61                 return;
   62         if (mapping && !mapping_mapped(mapping)) {
   63                 set_bit(PG_dcache_dirty, &(page)->flags);
   64                 return;
   65         }
   66 
   67         /*
   68          * We could delay the flush for the !page_mapping case too.  But that
   69          * case is for exec env/arg pages and those are %99 certainly going to
   70          * get faulted into the tlb (and thus flushed) anyways.
   71          */
   72         addr = (unsigned long) page_address(page);
   73         flush_data_cache_page(addr);
   74 }
   75 
   76 /* called by update_mmu_cache. */
   77 void __update_cache(struct vm_area_struct *vma, unsigned long address,
   78                 pte_t pte)
   79 {
   80         struct page *page;
   81         unsigned long pfn, addr;
   82         int exec = (vma->vm_flags & VM_EXEC);
   83 
   84         pfn = pte_pfn(pte);
   85         if (unlikely(!pfn_valid(pfn)))
   86                 return;
   87         page = pfn_to_page(pfn);
   88         if (page_mapping(page) && test_bit(PG_dcache_dirty, &(page)->flags)) {
   89                 addr = (unsigned long) page_address(page);
   90                 if (exec)
   91                         flush_data_cache_page(addr);
   92                 clear_bit(PG_dcache_dirty, &(page)->flags);
   93         }
   94 }
   95 
   96 static inline void setup_protection_map(void)
   97 {
   98         protection_map[0] = PAGE_NONE;
   99         protection_map[1] = PAGE_READONLY;
  100         protection_map[2] = PAGE_COPY;
  101         protection_map[3] = PAGE_COPY;
  102         protection_map[4] = PAGE_READONLY;
  103         protection_map[5] = PAGE_READONLY;
  104         protection_map[6] = PAGE_COPY;
  105         protection_map[7] = PAGE_COPY;
  106         protection_map[8] = PAGE_NONE;
  107         protection_map[9] = PAGE_READONLY;
  108         protection_map[10] = PAGE_SHARED;
  109         protection_map[11] = PAGE_SHARED;
  110         protection_map[12] = PAGE_READONLY;
  111         protection_map[13] = PAGE_READONLY;
  112         protection_map[14] = PAGE_SHARED;
  113         protection_map[15] = PAGE_SHARED;
  114 }
  115 
  116 void cpu_cache_init(void)
  117 {
  118         setup_protection_map();
  119 }
  120 
  121 void flush_icache_all(void)
  122 {
  123         __asm__ __volatile__(
  124         "la r8, flush_icache_all\n"
  125         "cache 0x10, [r8, 0]\n"
  126         "nop\nnop\nnop\nnop\nnop\nnop\n"
  127         : : : "r8");
  128 }
  129 
  130 void flush_dcache_all(void)
  131 {
  132         __asm__ __volatile__(
  133         "la r8, flush_dcache_all\n"
  134         "cache 0x1f, [r8, 0]\n"
  135         "nop\nnop\nnop\nnop\nnop\nnop\n"
  136         "cache 0x1a, [r8, 0]\n"
  137         "nop\nnop\nnop\nnop\nnop\nnop\n"
  138         : : : "r8");
  139 }
  140 
  141 void flush_cache_all(void)
  142 {
  143         __asm__ __volatile__(
  144         "la r8, flush_cache_all\n"
  145         "cache 0x10, [r8, 0]\n"
  146         "nop\nnop\nnop\nnop\nnop\nnop\n"
  147         "cache 0x1f, [r8, 0]\n"
  148         "nop\nnop\nnop\nnop\nnop\nnop\n"
  149         "cache 0x1a, [r8, 0]\n"
  150         "nop\nnop\nnop\nnop\nnop\nnop\n"
  151         : : : "r8");
  152 }
  153 
  154 void flush_cache_mm(struct mm_struct *mm)
  155 {
  156         if (!(mm->context))
  157                 return;
  158         flush_cache_all();
  159 }
  160 
  161 /*if we flush a range precisely , the processing may be very long.
  162 We must check each page in the range whether present. If the page is present,
  163 we can flush the range in the page. Be careful, the range may be cross two
  164 page, a page is present and another is not present.
  165 */
  166 /*
  167 The interface is provided in hopes that the port can find
  168 a suitably efficient method for removing multiple page
  169 sized regions from the cache.
  170 */
  171 void flush_cache_range(struct vm_area_struct *vma,
  172                 unsigned long start, unsigned long end)
  173 {
  174         struct mm_struct *mm = vma->vm_mm;
  175         int exec = vma->vm_flags & VM_EXEC;
  176         pgd_t *pgdp;
  177         pud_t *pudp;
  178         pmd_t *pmdp;
  179         pte_t *ptep;
  180 
  181         if (!(mm->context))
  182                 return;
  183 
  184         pgdp = pgd_offset(mm, start);
  185         pudp = pud_offset(pgdp, start);
  186         pmdp = pmd_offset(pudp, start);
  187         ptep = pte_offset(pmdp, start);
  188 
  189         while (start <= end) {
  190                 unsigned long tmpend;
  191                 pgdp = pgd_offset(mm, start);
  192                 pudp = pud_offset(pgdp, start);
  193                 pmdp = pmd_offset(pudp, start);
  194                 ptep = pte_offset(pmdp, start);
  195 
  196                 if (!(pte_val(*ptep) & _PAGE_PRESENT)) {
  197                         start = (start + PAGE_SIZE) & ~(PAGE_SIZE - 1);
  198                         continue;
  199                 }
  200                 tmpend = (start | (PAGE_SIZE-1)) > end ?
  201                                  end : (start | (PAGE_SIZE-1));
  202 
  203                 flush_dcache_range(start, tmpend);
  204                 if (exec)
  205                         flush_icache_range(start, tmpend);
  206                 start = (start + PAGE_SIZE) & ~(PAGE_SIZE - 1);
  207         }
  208 }
  209 
  210 void flush_cache_page(struct vm_area_struct *vma,
  211                 unsigned long addr, unsigned long pfn)
  212 {
  213         int exec = vma->vm_flags & VM_EXEC;
  214         unsigned long kaddr = 0xa0000000 | (pfn << PAGE_SHIFT);
  215 
  216         flush_dcache_range(kaddr, kaddr + PAGE_SIZE);
  217 
  218         if (exec)
  219                 flush_icache_range(kaddr, kaddr + PAGE_SIZE);
  220 }
  221 
  222 void flush_cache_sigtramp(unsigned long addr)
  223 {
  224         __asm__ __volatile__(
  225         "cache 0x02, [%0, 0]\n"
  226         "nop\nnop\nnop\nnop\nnop\n"
  227         "cache 0x02, [%0, 0x4]\n"
  228         "nop\nnop\nnop\nnop\nnop\n"
  229 
  230         "cache 0x0d, [%0, 0]\n"
  231         "nop\nnop\nnop\nnop\nnop\n"
  232         "cache 0x0d, [%0, 0x4]\n"
  233         "nop\nnop\nnop\nnop\nnop\n"
  234 
  235         "cache 0x1a, [%0, 0]\n"
  236         "nop\nnop\nnop\nnop\nnop\n"
  237         : : "r" (addr));
  238 }
  239 
  240 /*
  241 1. WB and invalid a cache line of Dcache
  242 2. Drain Write Buffer
  243 the range must be smaller than PAGE_SIZE
  244 */
  245 void flush_dcache_range(unsigned long start, unsigned long end)
  246 {
  247         int size, i;
  248 
  249         start = start & ~(L1_CACHE_BYTES - 1);
  250         end = end & ~(L1_CACHE_BYTES - 1);
  251         size = end - start;
  252         /* flush dcache to ram, and invalidate dcache lines. */
  253         for (i = 0; i < size; i += L1_CACHE_BYTES) {
  254                 __asm__ __volatile__(
  255                 "cache 0x0e, [%0, 0]\n"
  256                 "nop\nnop\nnop\nnop\nnop\n"
  257                 "cache 0x1a, [%0, 0]\n"
  258                 "nop\nnop\nnop\nnop\nnop\n"
  259                 : : "r" (start));
  260                 start += L1_CACHE_BYTES;
  261         }
  262 }
  263 
  264 void flush_icache_range(unsigned long start, unsigned long end)
  265 {
  266         int size, i;
  267         start = start & ~(L1_CACHE_BYTES - 1);
  268         end = end & ~(L1_CACHE_BYTES - 1);
  269 
  270         size = end - start;
  271         /* invalidate icache lines. */
  272         for (i = 0; i < size; i += L1_CACHE_BYTES) {
  273                 __asm__ __volatile__(
  274                 "cache 0x02, [%0, 0]\n"
  275                 "nop\nnop\nnop\nnop\nnop\n"
  276                 : : "r" (start));
  277                 start += L1_CACHE_BYTES;
  278         }
  279 }

Cache object: d5ee46db26542d1642c10a7de69b3e85


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.