123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
- *
- * Derived from MIPS:
- * Copyright (C) 1994 - 2003, 06, 07 by Ralf Baechle ([email protected])
- * Copyright (C) 2007 MIPS Technologies, Inc.
- */
- #include <linux/cacheinfo.h>
- #include <linux/export.h>
- #include <linux/fs.h>
- #include <linux/highmem.h>
- #include <linux/kernel.h>
- #include <linux/linkage.h>
- #include <linux/mm.h>
- #include <linux/sched.h>
- #include <linux/syscalls.h>
- #include <asm/bootinfo.h>
- #include <asm/cacheflush.h>
- #include <asm/cpu.h>
- #include <asm/cpu-features.h>
- #include <asm/loongarch.h>
- #include <asm/numa.h>
- #include <asm/processor.h>
- #include <asm/setup.h>
- void cache_error_setup(void)
- {
- extern char __weak except_vec_cex;
- set_merr_handler(0x0, &except_vec_cex, 0x80);
- }
- /*
- * LoongArch maintains ICache/DCache coherency by hardware,
- * we just need "ibar" to avoid instruction hazard here.
- */
- void local_flush_icache_range(unsigned long start, unsigned long end)
- {
- asm volatile ("\tibar 0\n"::);
- }
- EXPORT_SYMBOL(local_flush_icache_range);
- static void flush_cache_leaf(unsigned int leaf)
- {
- int i, j, nr_nodes;
- uint64_t addr = CSR_DMW0_BASE;
- struct cache_desc *cdesc = current_cpu_data.cache_leaves + leaf;
- nr_nodes = cache_private(cdesc) ? 1 : loongson_sysconf.nr_nodes;
- do {
- for (i = 0; i < cdesc->sets; i++) {
- for (j = 0; j < cdesc->ways; j++) {
- flush_cache_line(leaf, addr);
- addr++;
- }
- addr -= cdesc->ways;
- addr += cdesc->linesz;
- }
- addr += (1ULL << NODE_ADDRSPACE_SHIFT);
- } while (--nr_nodes > 0);
- }
- asmlinkage __visible void __flush_cache_all(void)
- {
- int leaf;
- struct cache_desc *cdesc = current_cpu_data.cache_leaves;
- unsigned int cache_present = current_cpu_data.cache_leaves_present;
- leaf = cache_present - 1;
- if (cache_inclusive(cdesc + leaf)) {
- flush_cache_leaf(leaf);
- return;
- }
- for (leaf = 0; leaf < cache_present; leaf++)
- flush_cache_leaf(leaf);
- }
- #define L1IUPRE (1 << 0)
- #define L1IUUNIFY (1 << 1)
- #define L1DPRE (1 << 2)
- #define LXIUPRE (1 << 0)
- #define LXIUUNIFY (1 << 1)
- #define LXIUPRIV (1 << 2)
- #define LXIUINCL (1 << 3)
- #define LXDPRE (1 << 4)
- #define LXDPRIV (1 << 5)
- #define LXDINCL (1 << 6)
- #define populate_cache_properties(cfg0, cdesc, level, leaf) \
- do { \
- unsigned int cfg1; \
- \
- cfg1 = read_cpucfg(LOONGARCH_CPUCFG17 + leaf); \
- if (level == 1) { \
- cdesc->flags |= CACHE_PRIVATE; \
- } else { \
- if (cfg0 & LXIUPRIV) \
- cdesc->flags |= CACHE_PRIVATE; \
- if (cfg0 & LXIUINCL) \
- cdesc->flags |= CACHE_INCLUSIVE; \
- } \
- cdesc->level = level; \
- cdesc->flags |= CACHE_PRESENT; \
- cdesc->ways = ((cfg1 & CPUCFG_CACHE_WAYS_M) >> CPUCFG_CACHE_WAYS) + 1; \
- cdesc->sets = 1 << ((cfg1 & CPUCFG_CACHE_SETS_M) >> CPUCFG_CACHE_SETS); \
- cdesc->linesz = 1 << ((cfg1 & CPUCFG_CACHE_LSIZE_M) >> CPUCFG_CACHE_LSIZE); \
- cdesc++; leaf++; \
- } while (0)
- void cpu_cache_init(void)
- {
- unsigned int leaf = 0, level = 1;
- unsigned int config = read_cpucfg(LOONGARCH_CPUCFG16);
- struct cache_desc *cdesc = current_cpu_data.cache_leaves;
- if (config & L1IUPRE) {
- if (config & L1IUUNIFY)
- cdesc->type = CACHE_TYPE_UNIFIED;
- else
- cdesc->type = CACHE_TYPE_INST;
- populate_cache_properties(config, cdesc, level, leaf);
- }
- if (config & L1DPRE) {
- cdesc->type = CACHE_TYPE_DATA;
- populate_cache_properties(config, cdesc, level, leaf);
- }
- config = config >> 3;
- for (level = 2; level <= CACHE_LEVEL_MAX; level++) {
- if (!config)
- break;
- if (config & LXIUPRE) {
- if (config & LXIUUNIFY)
- cdesc->type = CACHE_TYPE_UNIFIED;
- else
- cdesc->type = CACHE_TYPE_INST;
- populate_cache_properties(config, cdesc, level, leaf);
- }
- if (config & LXDPRE) {
- cdesc->type = CACHE_TYPE_DATA;
- populate_cache_properties(config, cdesc, level, leaf);
- }
- config = config >> 7;
- }
- BUG_ON(leaf > CACHE_LEAVES_MAX);
- current_cpu_data.cache_leaves_present = leaf;
- current_cpu_data.options |= LOONGARCH_CPU_PREFETCH;
- shm_align_mask = PAGE_SIZE - 1;
- }
- static const pgprot_t protection_map[16] = {
- [VM_NONE] = __pgprot(_CACHE_CC | _PAGE_USER |
- _PAGE_PROTNONE | _PAGE_NO_EXEC |
- _PAGE_NO_READ),
- [VM_READ] = __pgprot(_CACHE_CC | _PAGE_VALID |
- _PAGE_USER | _PAGE_PRESENT |
- _PAGE_NO_EXEC),
- [VM_WRITE] = __pgprot(_CACHE_CC | _PAGE_VALID |
- _PAGE_USER | _PAGE_PRESENT |
- _PAGE_NO_EXEC),
- [VM_WRITE | VM_READ] = __pgprot(_CACHE_CC | _PAGE_VALID |
- _PAGE_USER | _PAGE_PRESENT |
- _PAGE_NO_EXEC),
- [VM_EXEC] = __pgprot(_CACHE_CC | _PAGE_VALID |
- _PAGE_USER | _PAGE_PRESENT),
- [VM_EXEC | VM_READ] = __pgprot(_CACHE_CC | _PAGE_VALID |
- _PAGE_USER | _PAGE_PRESENT),
- [VM_EXEC | VM_WRITE] = __pgprot(_CACHE_CC | _PAGE_VALID |
- _PAGE_USER | _PAGE_PRESENT),
- [VM_EXEC | VM_WRITE | VM_READ] = __pgprot(_CACHE_CC | _PAGE_VALID |
- _PAGE_USER | _PAGE_PRESENT),
- [VM_SHARED] = __pgprot(_CACHE_CC | _PAGE_USER |
- _PAGE_PROTNONE | _PAGE_NO_EXEC |
- _PAGE_NO_READ),
- [VM_SHARED | VM_READ] = __pgprot(_CACHE_CC | _PAGE_VALID |
- _PAGE_USER | _PAGE_PRESENT |
- _PAGE_NO_EXEC),
- [VM_SHARED | VM_WRITE] = __pgprot(_CACHE_CC | _PAGE_VALID |
- _PAGE_USER | _PAGE_PRESENT |
- _PAGE_NO_EXEC | _PAGE_WRITE),
- [VM_SHARED | VM_WRITE | VM_READ] = __pgprot(_CACHE_CC | _PAGE_VALID |
- _PAGE_USER | _PAGE_PRESENT |
- _PAGE_NO_EXEC | _PAGE_WRITE),
- [VM_SHARED | VM_EXEC] = __pgprot(_CACHE_CC | _PAGE_VALID |
- _PAGE_USER | _PAGE_PRESENT),
- [VM_SHARED | VM_EXEC | VM_READ] = __pgprot(_CACHE_CC | _PAGE_VALID |
- _PAGE_USER | _PAGE_PRESENT),
- [VM_SHARED | VM_EXEC | VM_WRITE] = __pgprot(_CACHE_CC | _PAGE_VALID |
- _PAGE_USER | _PAGE_PRESENT |
- _PAGE_WRITE),
- [VM_SHARED | VM_EXEC | VM_WRITE | VM_READ] = __pgprot(_CACHE_CC | _PAGE_VALID |
- _PAGE_USER | _PAGE_PRESENT |
- _PAGE_WRITE)
- };
- DECLARE_VM_GET_PAGE_PROT
|