diff options
Diffstat (limited to 'arch/unicore32/mm')
-rw-r--r-- | arch/unicore32/mm/Kconfig | 41 | ||||
-rw-r--r-- | arch/unicore32/mm/Makefile | 14 | ||||
-rw-r--r-- | arch/unicore32/mm/alignment.c | 524 | ||||
-rw-r--r-- | arch/unicore32/mm/cache-ucv2.S | 209 | ||||
-rw-r--r-- | arch/unicore32/mm/extable.c | 21 | ||||
-rw-r--r-- | arch/unicore32/mm/fault.c | 481 | ||||
-rw-r--r-- | arch/unicore32/mm/flush.c | 94 | ||||
-rw-r--r-- | arch/unicore32/mm/init.c | 261 | ||||
-rw-r--r-- | arch/unicore32/mm/ioremap.c | 242 | ||||
-rw-r--r-- | arch/unicore32/mm/mm.h | 31 | ||||
-rw-r--r-- | arch/unicore32/mm/mmu.c | 513 | ||||
-rw-r--r-- | arch/unicore32/mm/pgd.c | 102 | ||||
-rw-r--r-- | arch/unicore32/mm/proc-macros.S | 142 | ||||
-rw-r--r-- | arch/unicore32/mm/proc-syms.c | 19 | ||||
-rw-r--r-- | arch/unicore32/mm/proc-ucv2.S | 131 | ||||
-rw-r--r-- | arch/unicore32/mm/tlb-ucv2.S | 86 |
16 files changed, 0 insertions, 2911 deletions
diff --git a/arch/unicore32/mm/Kconfig b/arch/unicore32/mm/Kconfig deleted file mode 100644 index 82759b6aba67..000000000000 --- a/arch/unicore32/mm/Kconfig +++ /dev/null @@ -1,41 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -comment "Processor Type" - -# Select CPU types depending on the architecture selected. This selects -# which CPUs we support in the kernel image, and the compiler instruction -# optimiser behaviour. - -config CPU_UCV2 - def_bool y - -comment "Processor Features" - -config CPU_ICACHE_DISABLE - bool "Disable I-Cache (I-bit)" - help - Say Y here to disable the processor instruction cache. Unless - you have a reason not to or are unsure, say N. - -config CPU_DCACHE_DISABLE - bool "Disable D-Cache (D-bit)" - help - Say Y here to disable the processor data cache. Unless - you have a reason not to or are unsure, say N. - -config CPU_DCACHE_WRITETHROUGH - bool "Force write through D-cache" - help - Say Y here to use the data cache in writethrough mode. Unless you - specifically require this or are unsure, say N. - -config CPU_DCACHE_LINE_DISABLE - bool "Disable D-cache line ops" - default y - help - Say Y here to disable the data cache line operations. - -config CPU_TLB_SINGLE_ENTRY_DISABLE - bool "Disable TLB single entry ops" - default y - help - Say Y here to disable the TLB single entry operations. diff --git a/arch/unicore32/mm/Makefile b/arch/unicore32/mm/Makefile deleted file mode 100644 index 8106260583ab..000000000000 --- a/arch/unicore32/mm/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Makefile for the linux unicore-specific parts of the memory manager. -# - -obj-y := extable.o fault.o init.o pgd.o mmu.o -obj-y += flush.o ioremap.o - -obj-$(CONFIG_MODULES) += proc-syms.o - -obj-$(CONFIG_ALIGNMENT_TRAP) += alignment.o - -obj-$(CONFIG_CPU_UCV2) += cache-ucv2.o tlb-ucv2.o proc-ucv2.o - diff --git a/arch/unicore32/mm/alignment.c b/arch/unicore32/mm/alignment.c deleted file mode 100644 index 2ea98f7a4156..000000000000 --- a/arch/unicore32/mm/alignment.c +++ /dev/null @@ -1,524 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * linux/arch/unicore32/mm/alignment.c - * - * Code specific to PKUnity SoC and UniCore ISA - * - * Copyright (C) 2001-2010 GUAN Xue-tao - */ -/* - * TODO: - * FPU ldm/stm not handling - */ -#include <linux/compiler.h> -#include <linux/kernel.h> -#include <linux/sched/debug.h> -#include <linux/errno.h> -#include <linux/string.h> -#include <linux/init.h> -#include <linux/sched.h> -#include <linux/uaccess.h> -#include <linux/pgtable.h> - -#include <asm/tlbflush.h> -#include <asm/unaligned.h> - -#include "mm.h" - -#define CODING_BITS(i) (i & 0xe0000120) - -#define LDST_P_BIT(i) (i & (1 << 28)) /* Preindex */ -#define LDST_U_BIT(i) (i & (1 << 27)) /* Add offset */ -#define LDST_W_BIT(i) (i & (1 << 25)) /* Writeback */ -#define LDST_L_BIT(i) (i & (1 << 24)) /* Load */ - -#define LDST_P_EQ_U(i) ((((i) ^ ((i) >> 1)) & (1 << 27)) == 0) - -#define LDSTH_I_BIT(i) (i & (1 << 26)) /* half-word immed */ -#define LDM_S_BIT(i) (i & (1 << 26)) /* write ASR from BSR */ -#define LDM_H_BIT(i) (i & (1 << 6)) /* select r0-r15 or r16-r31 */ - -#define RN_BITS(i) ((i >> 19) & 31) /* Rn */ -#define RD_BITS(i) ((i >> 14) & 31) /* Rd */ -#define RM_BITS(i) (i & 31) /* Rm */ - -#define REGMASK_BITS(i) (((i & 0x7fe00) >> 3) | (i & 0x3f)) -#define OFFSET_BITS(i) (i & 0x03fff) - -#define SHIFT_BITS(i) ((i >> 9) & 0x1f) -#define SHIFT_TYPE(i) (i & 0xc0) -#define SHIFT_LSL 0x00 -#define SHIFT_LSR 0x40 -#define SHIFT_ASR 0x80 -#define SHIFT_RORRRX 0xc0 - -union offset_union { - unsigned long un; - signed long sn; -}; - -#define TYPE_ERROR 0 -#define TYPE_FAULT 1 -#define TYPE_LDST 2 -#define TYPE_DONE 3 -#define TYPE_SWAP 4 -#define TYPE_COLS 5 /* Coprocessor load/store */ - -#define get8_unaligned_check(val, addr, err) \ - __asm__( \ - "1: ldb.u %1, [%2], #1\n" \ - "2:\n" \ - " .pushsection .fixup,\"ax\"\n" \ - " .align 2\n" \ - "3: mov %0, #1\n" \ - " b 2b\n" \ - " .popsection\n" \ - " .pushsection __ex_table,\"a\"\n" \ - " .align 3\n" \ - " .long 1b, 3b\n" \ - " .popsection\n" \ - : "=r" (err), "=&r" (val), "=r" (addr) \ - : "0" (err), "2" (addr)) - -#define get8t_unaligned_check(val, addr, err) \ - __asm__( \ - "1: ldb.u %1, [%2], #1\n" \ - "2:\n" \ - " .pushsection .fixup,\"ax\"\n" \ - " .align 2\n" \ - "3: mov %0, #1\n" \ - " b 2b\n" \ - " .popsection\n" \ - " .pushsection __ex_table,\"a\"\n" \ - " .align 3\n" \ - " .long 1b, 3b\n" \ - " .popsection\n" \ - : "=r" (err), "=&r" (val), "=r" (addr) \ - : "0" (err), "2" (addr)) - -#define get16_unaligned_check(val, addr) \ - do { \ - unsigned int err = 0, v, a = addr; \ - get8_unaligned_check(val, a, err); \ - get8_unaligned_check(v, a, err); \ - val |= v << 8; \ - if (err) \ - goto fault; \ - } while (0) - -#define put16_unaligned_check(val, addr) \ - do { \ - unsigned int err = 0, v = val, a = addr; \ - __asm__( \ - "1: stb.u %1, [%2], #1\n" \ - " mov %1, %1 >> #8\n" \ - "2: stb.u %1, [%2]\n" \ - "3:\n" \ - " .pushsection .fixup,\"ax\"\n" \ - " .align 2\n" \ - "4: mov %0, #1\n" \ - " b 3b\n" \ - " .popsection\n" \ - " .pushsection __ex_table,\"a\"\n" \ - " .align 3\n" \ - " .long 1b, 4b\n" \ - " .long 2b, 4b\n" \ - " .popsection\n" \ - : "=r" (err), "=&r" (v), "=&r" (a) \ - : "0" (err), "1" (v), "2" (a)); \ - if (err) \ - goto fault; \ - } while (0) - -#define __put32_unaligned_check(ins, val, addr) \ - do { \ - unsigned int err = 0, v = val, a = addr; \ - __asm__( \ - "1: "ins" %1, [%2], #1\n" \ - " mov %1, %1 >> #8\n" \ - "2: "ins" %1, [%2], #1\n" \ - " mov %1, %1 >> #8\n" \ - "3: "ins" %1, [%2], #1\n" \ - " mov %1, %1 >> #8\n" \ - "4: "ins" %1, [%2]\n" \ - "5:\n" \ - " .pushsection .fixup,\"ax\"\n" \ - " .align 2\n" \ - "6: mov %0, #1\n" \ - " b 5b\n" \ - " .popsection\n" \ - " .pushsection __ex_table,\"a\"\n" \ - " .align 3\n" \ - " .long 1b, 6b\n" \ - " .long 2b, 6b\n" \ - " .long 3b, 6b\n" \ - " .long 4b, 6b\n" \ - " .popsection\n" \ - : "=r" (err), "=&r" (v), "=&r" (a) \ - : "0" (err), "1" (v), "2" (a)); \ - if (err) \ - goto fault; \ - } while (0) - -#define get32_unaligned_check(val, addr) \ - do { \ - unsigned int err = 0, v, a = addr; \ - get8_unaligned_check(val, a, err); \ - get8_unaligned_check(v, a, err); \ - val |= v << 8; \ - get8_unaligned_check(v, a, err); \ - val |= v << 16; \ - get8_unaligned_check(v, a, err); \ - val |= v << 24; \ - if (err) \ - goto fault; \ - } while (0) - -#define put32_unaligned_check(val, addr) \ - __put32_unaligned_check("stb.u", val, addr) - -#define get32t_unaligned_check(val, addr) \ - do { \ - unsigned int err = 0, v, a = addr; \ - get8t_unaligned_check(val, a, err); \ - get8t_unaligned_check(v, a, err); \ - val |= v << 8; \ - get8t_unaligned_check(v, a, err); \ - val |= v << 16; \ - get8t_unaligned_check(v, a, err); \ - val |= v << 24; \ - if (err) \ - goto fault; \ - } while (0) - -#define put32t_unaligned_check(val, addr) \ - __put32_unaligned_check("stb.u", val, addr) - -static void -do_alignment_finish_ldst(unsigned long addr, unsigned long instr, - struct pt_regs *regs, union offset_union offset) -{ - if (!LDST_U_BIT(instr)) - offset.un = -offset.un; - - if (!LDST_P_BIT(instr)) - addr += offset.un; - - if (!LDST_P_BIT(instr) || LDST_W_BIT(instr)) - regs->uregs[RN_BITS(instr)] = addr; -} - -static int -do_alignment_ldrhstrh(unsigned long addr, unsigned long instr, - struct pt_regs *regs) -{ - unsigned int rd = RD_BITS(instr); - - /* old value 0x40002120, can't judge swap instr correctly */ - if ((instr & 0x4b003fe0) == 0x40000120) - goto swp; - - if (LDST_L_BIT(instr)) { - unsigned long val; - get16_unaligned_check(val, addr); - - /* signed half-word? */ - if (instr & 0x80) - val = (signed long)((signed short)val); - - regs->uregs[rd] = val; - } else - put16_unaligned_check(regs->uregs[rd], addr); - - return TYPE_LDST; - -swp: - /* only handle swap word - * for swap byte should not active this alignment exception */ - get32_unaligned_check(regs->uregs[RD_BITS(instr)], addr); - put32_unaligned_check(regs->uregs[RM_BITS(instr)], addr); - return TYPE_SWAP; - -fault: - return TYPE_FAULT; -} - -static int -do_alignment_ldrstr(unsigned long addr, unsigned long instr, - struct pt_regs *regs) -{ - unsigned int rd = RD_BITS(instr); - - if (!LDST_P_BIT(instr) && LDST_W_BIT(instr)) - goto trans; - - if (LDST_L_BIT(instr)) - get32_unaligned_check(regs->uregs[rd], addr); - else - put32_unaligned_check(regs->uregs[rd], addr); - return TYPE_LDST; - -trans: - if (LDST_L_BIT(instr)) - get32t_unaligned_check(regs->uregs[rd], addr); - else - put32t_unaligned_check(regs->uregs[rd], addr); - return TYPE_LDST; - -fault: - return TYPE_FAULT; -} - -/* - * LDM/STM alignment handler. - * - * There are 4 variants of this instruction: - * - * B = rn pointer before instruction, A = rn pointer after instruction - * ------ increasing address -----> - * | | r0 | r1 | ... | rx | | - * PU = 01 B A - * PU = 11 B A - * PU = 00 A B - * PU = 10 A B - */ -static int -do_alignment_ldmstm(unsigned long addr, unsigned long instr, - struct pt_regs *regs) -{ - unsigned int rd, rn, pc_correction, reg_correction, nr_regs, regbits; - unsigned long eaddr, newaddr; - - if (LDM_S_BIT(instr)) - goto bad; - - pc_correction = 4; /* processor implementation defined */ - - /* count the number of registers in the mask to be transferred */ - nr_regs = hweight16(REGMASK_BITS(instr)) * 4; - - rn = RN_BITS(instr); - newaddr = eaddr = regs->uregs[rn]; - - if (!LDST_U_BIT(instr)) - nr_regs = -nr_regs; - newaddr += nr_regs; - if (!LDST_U_BIT(instr)) - eaddr = newaddr; - - if (LDST_P_EQ_U(instr)) /* U = P */ - eaddr += 4; - - /* - * This is a "hint" - we already have eaddr worked out by the - * processor for us. - */ - if (addr != eaddr) { - printk(KERN_ERR "LDMSTM: PC = %08lx, instr = %08lx, " - "addr = %08lx, eaddr = %08lx\n", - instruction_pointer(regs), instr, addr, eaddr); - show_regs(regs); - } - - if (LDM_H_BIT(instr)) - reg_correction = 0x10; - else - reg_correction = 0x00; - - for (regbits = REGMASK_BITS(instr), rd = 0; regbits; - regbits >>= 1, rd += 1) - if (regbits & 1) { - if (LDST_L_BIT(instr)) - get32_unaligned_check(regs-> - uregs[rd + reg_correction], eaddr); - else - put32_unaligned_check(regs-> - uregs[rd + reg_correction], eaddr); - eaddr += 4; - } - - if (LDST_W_BIT(instr)) - regs->uregs[rn] = newaddr; - return TYPE_DONE; - -fault: - regs->UCreg_pc -= pc_correction; - return TYPE_FAULT; - -bad: - printk(KERN_ERR "Alignment trap: not handling ldm with s-bit set\n"); - return TYPE_ERROR; -} - -static int -do_alignment(unsigned long addr, unsigned int error_code, struct pt_regs *regs) -{ - union offset_union offset; - unsigned long instr, instrptr; - int (*handler) (unsigned long addr, unsigned long instr, - struct pt_regs *regs); - unsigned int type; - - instrptr = instruction_pointer(regs); - if (instrptr >= PAGE_OFFSET) - instr = *(unsigned long *)instrptr; - else { - __asm__ __volatile__( - "ldw.u %0, [%1]\n" - : "=&r"(instr) - : "r"(instrptr)); - } - - regs->UCreg_pc += 4; - - switch (CODING_BITS(instr)) { - case 0x40000120: /* ldrh or strh */ - if (LDSTH_I_BIT(instr)) - offset.un = (instr & 0x3e00) >> 4 | (instr & 31); - else - offset.un = regs->uregs[RM_BITS(instr)]; - handler = do_alignment_ldrhstrh; - break; - - case 0x60000000: /* ldr or str immediate */ - case 0x60000100: /* ldr or str immediate */ - case 0x60000020: /* ldr or str immediate */ - case 0x60000120: /* ldr or str immediate */ - offset.un = OFFSET_BITS(instr); - handler = do_alignment_ldrstr; - break; - - case 0x40000000: /* ldr or str register */ - offset.un = regs->uregs[RM_BITS(instr)]; - { - unsigned int shiftval = SHIFT_BITS(instr); - - switch (SHIFT_TYPE(instr)) { - case SHIFT_LSL: - offset.un <<= shiftval; - break; - - case SHIFT_LSR: - offset.un >>= shiftval; - break; - - case SHIFT_ASR: - offset.sn >>= shiftval; - break; - - case SHIFT_RORRRX: - if (shiftval == 0) { - offset.un >>= 1; - if (regs->UCreg_asr & PSR_C_BIT) - offset.un |= 1 << 31; - } else - offset.un = offset.un >> shiftval | - offset.un << (32 - shiftval); - break; - } - } - handler = do_alignment_ldrstr; - break; - - case 0x80000000: /* ldm or stm */ - case 0x80000020: /* ldm or stm */ - handler = do_alignment_ldmstm; - break; - - default: - goto bad; - } - - type = handler(addr, instr, regs); - - if (type == TYPE_ERROR || type == TYPE_FAULT) - goto bad_or_fault; - - if (type == TYPE_LDST) - do_alignment_finish_ldst(addr, instr, regs, offset); - - return 0; - -bad_or_fault: - if (type == TYPE_ERROR) - goto bad; - regs->UCreg_pc -= 4; - /* - * We got a fault - fix it up, or die. - */ - do_bad_area(addr, error_code, regs); - return 0; - -bad: - /* - * Oops, we didn't handle the instruction. - * However, we must handle fpu instr firstly. - */ -#ifdef CONFIG_UNICORE_FPU_F64 - /* handle co.load/store */ -#define CODING_COLS 0xc0000000 -#define COLS_OFFSET_BITS(i) (i & 0x1FF) -#define COLS_L_BITS(i) (i & (1<<24)) -#define COLS_FN_BITS(i) ((i>>14) & 31) - if ((instr & 0xe0000000) == CODING_COLS) { - unsigned int fn = COLS_FN_BITS(instr); - unsigned long val = 0; - if (COLS_L_BITS(instr)) { - get32t_unaligned_check(val, addr); - switch (fn) { -#define ASM_MTF(n) case n: \ - __asm__ __volatile__("MTF %0, F" __stringify(n) \ - : : "r"(val)); \ - break; - ASM_MTF(0); ASM_MTF(1); ASM_MTF(2); ASM_MTF(3); - ASM_MTF(4); ASM_MTF(5); ASM_MTF(6); ASM_MTF(7); - ASM_MTF(8); ASM_MTF(9); ASM_MTF(10); ASM_MTF(11); - ASM_MTF(12); ASM_MTF(13); ASM_MTF(14); ASM_MTF(15); - ASM_MTF(16); ASM_MTF(17); ASM_MTF(18); ASM_MTF(19); - ASM_MTF(20); ASM_MTF(21); ASM_MTF(22); ASM_MTF(23); - ASM_MTF(24); ASM_MTF(25); ASM_MTF(26); ASM_MTF(27); - ASM_MTF(28); ASM_MTF(29); ASM_MTF(30); ASM_MTF(31); -#undef ASM_MTF - } - } else { - switch (fn) { -#define ASM_MFF(n) case n: \ - __asm__ __volatile__("MFF %0, F" __stringify(n) \ - : : "r"(val)); \ - break; - ASM_MFF(0); ASM_MFF(1); ASM_MFF(2); ASM_MFF(3); - ASM_MFF(4); ASM_MFF(5); ASM_MFF(6); ASM_MFF(7); - ASM_MFF(8); ASM_MFF(9); ASM_MFF(10); ASM_MFF(11); - ASM_MFF(12); ASM_MFF(13); ASM_MFF(14); ASM_MFF(15); - ASM_MFF(16); ASM_MFF(17); ASM_MFF(18); ASM_MFF(19); - ASM_MFF(20); ASM_MFF(21); ASM_MFF(22); ASM_MFF(23); - ASM_MFF(24); ASM_MFF(25); ASM_MFF(26); ASM_MFF(27); - ASM_MFF(28); ASM_MFF(29); ASM_MFF(30); ASM_MFF(31); -#undef ASM_MFF - } - put32t_unaligned_check(val, addr); - } - return TYPE_COLS; - } -fault: - return TYPE_FAULT; -#endif - printk(KERN_ERR "Alignment trap: not handling instruction " - "%08lx at [<%08lx>]\n", instr, instrptr); - return 1; -} - -/* - * This needs to be done after sysctl_init, otherwise sys/ will be - * overwritten. Actually, this shouldn't be in sys/ at all since - * it isn't a sysctl, and it doesn't contain sysctl information. - */ -static int __init alignment_init(void) -{ - hook_fault_code(1, do_alignment, SIGBUS, BUS_ADRALN, - "alignment exception"); - - return 0; -} - -fs_initcall(alignment_init); diff --git a/arch/unicore32/mm/cache-ucv2.S b/arch/unicore32/mm/cache-ucv2.S deleted file mode 100644 index 2108837d6f4f..000000000000 --- a/arch/unicore32/mm/cache-ucv2.S +++ /dev/null @@ -1,209 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * linux/arch/unicore32/mm/cache-ucv2.S - * - * Code specific to PKUnity SoC and UniCore ISA - * - * Copyright (C) 2001-2010 GUAN Xue-tao - * - * This is the "shell" of the UniCore-v2 processor support. - */ -#include <linux/linkage.h> -#include <linux/init.h> -#include <asm/assembler.h> -#include <asm/page.h> - -#include "proc-macros.S" - -/* - * __cpuc_flush_icache_all() - * __cpuc_flush_kern_all() - * __cpuc_flush_user_all() - * - * Flush the entire cache. - */ -ENTRY(__cpuc_flush_icache_all) - /*FALLTHROUGH*/ -ENTRY(__cpuc_flush_kern_all) - /*FALLTHROUGH*/ -ENTRY(__cpuc_flush_user_all) - mov r0, #0 - movc p0.c5, r0, #14 @ Dcache flush all - nop8 - - mov r0, #0 - movc p0.c5, r0, #20 @ Icache invalidate all - nop8 - - mov pc, lr - -/* - * __cpuc_flush_user_range(start, end, flags) - * - * Flush a range of TLB entries in the specified address space. - * - * - start - start address (may not be aligned) - * - end - end address (exclusive, may not be aligned) - * - flags - vm_area_struct flags describing address space - */ -ENTRY(__cpuc_flush_user_range) - cxor.a r2, #0 - beq __cpuc_dma_flush_range - -#ifndef CONFIG_CPU_DCACHE_LINE_DISABLE - andn r0, r0, #CACHE_LINESIZE - 1 @ Safety check - sub r1, r1, r0 - csub.a r1, #MAX_AREA_SIZE - bsg 2f - - andn r1, r1, #CACHE_LINESIZE - 1 - add r1, r1, #CACHE_LINESIZE - -101: dcacheline_flush r0, r11, r12 - - add r0, r0, #CACHE_LINESIZE - sub.a r1, r1, #CACHE_LINESIZE - bns 101b - b 3f -#endif -2: mov ip, #0 - movc p0.c5, ip, #14 @ Dcache flush all - nop8 - -3: mov ip, #0 - movc p0.c5, ip, #20 @ Icache invalidate all - nop8 - - mov pc, lr - -/* - * __cpuc_coherent_kern_range(start,end) - * __cpuc_coherent_user_range(start,end) - * - * Ensure that the I and D caches are coherent within specified - * region. This is typically used when code has been written to - * a memory region, and will be executed. - * - * - start - virtual start address of region - * - end - virtual end address of region - */ -ENTRY(__cpuc_coherent_kern_range) - /* FALLTHROUGH */ -ENTRY(__cpuc_coherent_user_range) -#ifndef CONFIG_CPU_DCACHE_LINE_DISABLE - andn r0, r0, #CACHE_LINESIZE - 1 @ Safety check - sub r1, r1, r0 - csub.a r1, #MAX_AREA_SIZE - bsg 2f - - andn r1, r1, #CACHE_LINESIZE - 1 - add r1, r1, #CACHE_LINESIZE - - @ r0 va2pa r10 - mov r9, #PAGE_SZ - sub r9, r9, #1 @ PAGE_MASK -101: va2pa r0, r10, r11, r12, r13, 2f @ r10 is PA - b 103f -102: cand.a r0, r9 - beq 101b - -103: movc p0.c5, r10, #11 @ Dcache clean line of R10 - nop8 - - add r0, r0, #CACHE_LINESIZE - add r10, r10, #CACHE_LINESIZE - sub.a r1, r1, #CACHE_LINESIZE - bns 102b - b 3f -#endif -2: mov ip, #0 - movc p0.c5, ip, #10 @ Dcache clean all - nop8 - -3: mov ip, #0 - movc p0.c5, ip, #20 @ Icache invalidate all - nop8 - - mov pc, lr - -/* - * __cpuc_flush_kern_dcache_area(void *addr, size_t size) - * - * - addr - kernel address - * - size - region size - */ -ENTRY(__cpuc_flush_kern_dcache_area) - mov ip, #0 - movc p0.c5, ip, #14 @ Dcache flush all - nop8 - mov pc, lr - -/* - * __cpuc_dma_clean_range(start,end) - * - start - virtual start address of region - * - end - virtual end address of region - */ -ENTRY(__cpuc_dma_clean_range) -#ifndef CONFIG_CPU_DCACHE_LINE_DISABLE - andn r0, r0, #CACHE_LINESIZE - 1 - sub r1, r1, r0 - andn r1, r1, #CACHE_LINESIZE - 1 - add r1, r1, #CACHE_LINESIZE - - csub.a r1, #MAX_AREA_SIZE - bsg 2f - - @ r0 va2pa r10 - mov r9, #PAGE_SZ - sub r9, r9, #1 @ PAGE_MASK -101: va2pa r0, r10, r11, r12, r13, 2f @ r10 is PA - b 1f -102: cand.a r0, r9 - beq 101b - -1: movc p0.c5, r10, #11 @ Dcache clean line of R10 - nop8 - add r0, r0, #CACHE_LINESIZE - add r10, r10, #CACHE_LINESIZE - sub.a r1, r1, #CACHE_LINESIZE - bns 102b - mov pc, lr -#endif -2: mov ip, #0 - movc p0.c5, ip, #10 @ Dcache clean all - nop8 - - mov pc, lr - -/* - * __cpuc_dma_inv_range(start,end) - * __cpuc_dma_flush_range(start,end) - * - start - virtual start address of region - * - end - virtual end address of region - */ -__cpuc_dma_inv_range: - /* FALLTHROUGH */ -ENTRY(__cpuc_dma_flush_range) -#ifndef CONFIG_CPU_DCACHE_LINE_DISABLE - andn r0, r0, #CACHE_LINESIZE - 1 - sub r1, r1, r0 - andn r1, r1, #CACHE_LINESIZE - 1 - add r1, r1, #CACHE_LINESIZE - - csub.a r1, #MAX_AREA_SIZE - bsg 2f - - @ r0 va2pa r10 -101: dcacheline_flush r0, r11, r12 - - add r0, r0, #CACHE_LINESIZE - sub.a r1, r1, #CACHE_LINESIZE - bns 101b - mov pc, lr -#endif -2: mov ip, #0 - movc p0.c5, ip, #14 @ Dcache flush all - nop8 - - mov pc, lr - diff --git a/arch/unicore32/mm/extable.c b/arch/unicore32/mm/extable.c deleted file mode 100644 index e53352b41c4a..000000000000 --- a/arch/unicore32/mm/extable.c +++ /dev/null @@ -1,21 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * linux/arch/unicore32/mm/extable.c - * - * Code specific to PKUnity SoC and UniCore ISA - * - * Copyright (C) 2001-2010 GUAN Xue-tao - */ -#include <linux/extable.h> -#include <linux/uaccess.h> - -int fixup_exception(struct pt_regs *regs) -{ - const struct exception_table_entry *fixup; - - fixup = search_exception_tables(instruction_pointer(regs)); - if (fixup) - regs->UCreg_pc = fixup->fixup; - - return fixup != NULL; -} diff --git a/arch/unicore32/mm/fault.c b/arch/unicore32/mm/fault.c deleted file mode 100644 index 7654bddde133..000000000000 --- a/arch/unicore32/mm/fault.c +++ /dev/null @@ -1,481 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * linux/arch/unicore32/mm/fault.c - * - * Code specific to PKUnity SoC and UniCore ISA - * - * Copyright (C) 2001-2010 GUAN Xue-tao - */ -#include <linux/extable.h> -#include <linux/signal.h> -#include <linux/mm.h> -#include <linux/hardirq.h> -#include <linux/init.h> -#include <linux/kprobes.h> -#include <linux/uaccess.h> -#include <linux/page-flags.h> -#include <linux/sched/signal.h> -#include <linux/io.h> - -#include <asm/tlbflush.h> - -/* - * Fault status register encodings. We steal bit 31 for our own purposes. - */ -#define FSR_LNX_PF (1 << 31) - -static inline int fsr_fs(unsigned int fsr) -{ - /* xyabcde will be abcde+xy */ - return (fsr & 31) + ((fsr & (3 << 5)) >> 5); -} - -/* - * This is useful to dump out the page tables associated with - * 'addr' in mm 'mm'. - */ -void show_pte(struct mm_struct *mm, unsigned long addr) -{ - pgd_t *pgd; - - if (!mm) - mm = &init_mm; - - printk(KERN_ALERT "pgd = %p\n", mm->pgd); - pgd = pgd_offset(mm, addr); - printk(KERN_ALERT "[%08lx] *pgd=%08lx", addr, pgd_val(*pgd)); - - do { - pmd_t *pmd; - pte_t *pte; - - if (pgd_none(*pgd)) - break; - - if (pgd_bad(*pgd)) { - printk("(bad)"); - break; - } - - pmd = pmd_offset((pud_t *) pgd, addr); - if (PTRS_PER_PMD != 1) - printk(", *pmd=%08lx", pmd_val(*pmd)); - - if (pmd_none(*pmd)) - break; - - if (pmd_bad(*pmd)) { - printk("(bad)"); - break; - } - - /* We must not map this if we have highmem enabled */ - if (PageHighMem(pfn_to_page(pmd_val(*pmd) >> PAGE_SHIFT))) - break; - - pte = pte_offset_map(pmd, addr); - printk(", *pte=%08lx", pte_val(*pte)); - pte_unmap(pte); - } while (0); - - printk("\n"); -} - -/* - * Oops. The kernel tried to access some page that wasn't present. - */ -static void __do_kernel_fault(struct mm_struct *mm, unsigned long addr, - unsigned int fsr, struct pt_regs *regs) -{ - /* - * Are we prepared to handle this kernel fault? - */ - if (fixup_exception(regs)) - return; - - /* - * No handler, we'll have to terminate things with extreme prejudice. - */ - bust_spinlocks(1); - printk(KERN_ALERT - "Unable to handle kernel %s at virtual address %08lx\n", - (addr < PAGE_SIZE) ? "NULL pointer dereference" : - "paging request", addr); - - show_pte(mm, addr); - die("Oops", regs, fsr); - bust_spinlocks(0); - do_exit(SIGKILL); -} - -/* - * Something tried to access memory that isn't in our memory map.. - * User mode accesses just cause a SIGSEGV - */ -static void __do_user_fault(unsigned long addr, unsigned int fsr, - unsigned int sig, int code, struct pt_regs *regs) -{ - struct task_struct *tsk = current; - - tsk->thread.address = addr; - tsk->thread.error_code = fsr; - tsk->thread.trap_no = 14; - force_sig_fault(sig, code, (void __user *)addr); -} - -void do_bad_area(unsigned long addr, unsigned int fsr, struct pt_regs *regs) -{ - struct task_struct *tsk = current; - struct mm_struct *mm = tsk->active_mm; - - /* - * If we are in kernel mode at this point, we - * have no context to handle this fault with. - */ - if (user_mode(regs)) - __do_user_fault(addr, fsr, SIGSEGV, SEGV_MAPERR, regs); - else - __do_kernel_fault(mm, addr, fsr, regs); -} - -#define VM_FAULT_BADMAP 0x010000 -#define VM_FAULT_BADACCESS 0x020000 - -/* - * Check that the permissions on the VMA allow for the fault which occurred. - * If we encountered a write fault, we must have write permission, otherwise - * we allow any permission. - */ -static inline bool access_error(unsigned int fsr, struct vm_area_struct *vma) -{ - unsigned int mask = VM_ACCESS_FLAGS; - - if (!(fsr ^ 0x12)) /* write? */ - mask = VM_WRITE; - if (fsr & FSR_LNX_PF) - mask = VM_EXEC; - - return vma->vm_flags & mask ? false : true; -} - -static vm_fault_t __do_pf(struct mm_struct *mm, unsigned long addr, - unsigned int fsr, unsigned int flags, struct task_struct *tsk) -{ - struct vm_area_struct *vma; - vm_fault_t fault; - - vma = find_vma(mm, addr); - fault = VM_FAULT_BADMAP; - if (unlikely(!vma)) - goto out; - if (unlikely(vma->vm_start > addr)) - goto check_stack; - - /* - * Ok, we have a good vm_area for this - * memory access, so we can handle it. - */ -good_area: - if (access_error(fsr, vma)) { - fault = VM_FAULT_BADACCESS; - goto out; - } - - /* - * If for any reason at all we couldn't handle the fault, make - * sure we exit gracefully rather than endlessly redo the fault. - */ - fault = handle_mm_fault(vma, addr & PAGE_MASK, flags); - return fault; - -check_stack: - if (vma->vm_flags & VM_GROWSDOWN && !expand_stack(vma, addr)) - goto good_area; -out: - return fault; -} - -static int do_pf(unsigned long addr, unsigned int fsr, struct pt_regs *regs) -{ - struct task_struct *tsk; - struct mm_struct *mm; - int sig, code; - vm_fault_t fault; - unsigned int flags = FAULT_FLAG_DEFAULT; - - tsk = current; - mm = tsk->mm; - - /* - * If we're in an interrupt or have no user - * context, we must not take the fault.. - */ - if (faulthandler_disabled() || !mm) - goto no_context; - - if (user_mode(regs)) - flags |= FAULT_FLAG_USER; - if (!(fsr ^ 0x12)) - flags |= FAULT_FLAG_WRITE; - - /* - * As per x86, we may deadlock here. However, since the kernel only - * validly references user space from well defined areas of the code, - * we can bug out early if this is from code which shouldn't. - */ - if (!mmap_read_trylock(mm)) { - if (!user_mode(regs) - && !search_exception_tables(regs->UCreg_pc)) - goto no_context; -retry: - mmap_read_lock(mm); - } else { - /* - * The above down_read_trylock() might have succeeded in - * which case, we'll have missed the might_sleep() from - * down_read() - */ - might_sleep(); -#ifdef CONFIG_DEBUG_VM - if (!user_mode(regs) && - !search_exception_tables(regs->UCreg_pc)) - goto no_context; -#endif - } - - fault = __do_pf(mm, addr, fsr, flags, tsk); - - /* If we need to retry but a fatal signal is pending, handle the - * signal first. We do not need to release the mmap_lock because - * it would already be released in __lock_page_or_retry in - * mm/filemap.c. */ - if (fault_signal_pending(fault, regs)) - return 0; - - if (!(fault & VM_FAULT_ERROR) && (flags & FAULT_FLAG_ALLOW_RETRY)) { - if (fault & VM_FAULT_MAJOR) - tsk->maj_flt++; - else - tsk->min_flt++; - if (fault & VM_FAULT_RETRY) { - flags |= FAULT_FLAG_TRIED; - goto retry; - } - } - - mmap_read_unlock(mm); - - /* - * Handle the "normal" case first - VM_FAULT_MAJOR - */ - if (likely(!(fault & - (VM_FAULT_ERROR | VM_FAULT_BADMAP | VM_FAULT_BADACCESS)))) - return 0; - - /* - * If we are in kernel mode at this point, we - * have no context to handle this fault with. - */ - if (!user_mode(regs)) - goto no_context; - - if (fault & VM_FAULT_OOM) { - /* - * We ran out of memory, call the OOM killer, and return to - * userspace (which will retry the fault, or kill us if we - * got oom-killed) - */ - pagefault_out_of_memory(); - return 0; - } - - if (fault & VM_FAULT_SIGBUS) { - /* - * We had some memory, but were unable to - * successfully fix up this page fault. - */ - sig = SIGBUS; - code = BUS_ADRERR; - } else { - /* - * Something tried to access memory that - * isn't in our memory map.. - */ - sig = SIGSEGV; - code = fault == VM_FAULT_BADACCESS ? SEGV_ACCERR : SEGV_MAPERR; - } - - __do_user_fault(addr, fsr, sig, code, regs); - return 0; - -no_context: - __do_kernel_fault(mm, addr, fsr, regs); - return 0; -} - -/* - * First Level Translation Fault Handler - * - * We enter here because the first level page table doesn't contain - * a valid entry for the address. - * - * If the address is in kernel space (>= TASK_SIZE), then we are - * probably faulting in the vmalloc() area. - * - * If the init_task's first level page tables contains the relevant - * entry, we copy the it to this task. If not, we send the process - * a signal, fixup the exception, or oops the kernel. - * - * NOTE! We MUST NOT take any locks for this case. We may be in an - * interrupt or a critical region, and should only copy the information - * from the master page table, nothing more. - */ -static int do_ifault(unsigned long addr, unsigned int fsr, struct pt_regs *regs) -{ - unsigned int index; - pgd_t *pgd, *pgd_k; - pmd_t *pmd, *pmd_k; - - if (addr < TASK_SIZE) - return do_pf(addr, fsr, regs); - - if (user_mode(regs)) - goto bad_area; - - index = pgd_index(addr); - - pgd = cpu_get_pgd() + index; - pgd_k = init_mm.pgd + index; - - if (pgd_none(*pgd_k)) - goto bad_area; - - pmd_k = pmd_offset((pud_t *) pgd_k, addr); - pmd = pmd_offset((pud_t *) pgd, addr); - - if (pmd_none(*pmd_k)) - goto bad_area; - - set_pmd(pmd, *pmd_k); - flush_pmd_entry(pmd); - return 0; - -bad_area: - do_bad_area(addr, fsr, regs); - return 0; -} - -/* - * This abort handler always returns "fault". - */ -static int do_bad(unsigned long addr, unsigned int fsr, struct pt_regs *regs) -{ - return 1; -} - -static int do_good(unsigned long addr, unsigned int fsr, struct pt_regs *regs) -{ - unsigned int res1, res2; - - printk("dabt exception but no error!\n"); - - __asm__ __volatile__( - "mff %0,f0\n" - "mff %1,f1\n" - : "=r"(res1), "=r"(res2) - : - : "memory"); - - printk(KERN_EMERG "r0 :%08x r1 :%08x\n", res1, res2); - panic("shut up\n"); - return 0; -} - -static struct fsr_info { - int (*fn) (unsigned long addr, unsigned int fsr, struct pt_regs *regs); - int sig; - int code; - const char *name; -} fsr_info[] = { - /* - * The following are the standard Unicore-I and UniCore-II aborts. - */ - { do_good, SIGBUS, 0, "no error" }, - { do_bad, SIGBUS, BUS_ADRALN, "alignment exception" }, - { do_bad, SIGBUS, BUS_OBJERR, "external exception" }, - { do_bad, SIGBUS, 0, "burst operation" }, - { do_bad, SIGBUS, 0, "unknown 00100" }, - { do_ifault, SIGSEGV, SEGV_MAPERR, "2nd level pt non-exist"}, - { do_bad, SIGBUS, 0, "2nd lvl large pt non-exist" }, - { do_bad, SIGBUS, 0, "invalid pte" }, - { do_pf, SIGSEGV, SEGV_MAPERR, "page miss" }, - { do_bad, SIGBUS, 0, "middle page miss" }, - { do_bad, SIGBUS, 0, "large page miss" }, - { do_pf, SIGSEGV, SEGV_MAPERR, "super page (section) miss" }, - { do_bad, SIGBUS, 0, "unknown 01100" }, - { do_bad, SIGBUS, 0, "unknown 01101" }, - { do_bad, SIGBUS, 0, "unknown 01110" }, - { do_bad, SIGBUS, 0, "unknown 01111" }, - { do_bad, SIGBUS, 0, "addr: up 3G or IO" }, - { do_pf, SIGSEGV, SEGV_ACCERR, "read unreadable addr" }, - { do_pf, SIGSEGV, SEGV_ACCERR, "write unwriteable addr"}, - { do_pf, SIGSEGV, SEGV_ACCERR, "exec unexecutable addr"}, - { do_bad, SIGBUS, 0, "unknown 10100" }, - { do_bad, SIGBUS, 0, "unknown 10101" }, - { do_bad, SIGBUS, 0, "unknown 10110" }, - { do_bad, SIGBUS, 0, "unknown 10111" }, - { do_bad, SIGBUS, 0, "unknown 11000" }, - { do_bad, SIGBUS, 0, "unknown 11001" }, - { do_bad, SIGBUS, 0, "unknown 11010" }, - { do_bad, SIGBUS, 0, "unknown 11011" }, - { do_bad, SIGBUS, 0, "unknown 11100" }, - { do_bad, SIGBUS, 0, "unknown 11101" }, - { do_bad, SIGBUS, 0, "unknown 11110" }, - { do_bad, SIGBUS, 0, "unknown 11111" } -}; - -void __init hook_fault_code(int nr, - int (*fn) (unsigned long, unsigned int, struct pt_regs *), - int sig, int code, const char *name) -{ - if (nr < 0 || nr >= ARRAY_SIZE(fsr_info)) - BUG(); - - fsr_info[nr].fn = fn; - fsr_info[nr].sig = sig; - fsr_info[nr].code = code; - fsr_info[nr].name = name; -} - -/* - * Dispatch a data abort to the relevant handler. - */ -asmlinkage void do_DataAbort(unsigned long addr, unsigned int fsr, - struct pt_regs *regs) -{ - const struct fsr_info *inf = fsr_info + fsr_fs(fsr); - - if (!inf->fn(addr, fsr & ~FSR_LNX_PF, regs)) - return; - - printk(KERN_ALERT "Unhandled fault: %s (0x%03x) at 0x%08lx\n", - inf->name, fsr, addr); - - uc32_notify_die("", regs, inf->sig, inf->code, (void __user *)addr, - fsr, 0); -} - -asmlinkage void do_PrefetchAbort(unsigned long addr, - unsigned int ifsr, struct pt_regs *regs) -{ - const struct fsr_info *inf = fsr_info + fsr_fs(ifsr); - - if (!inf->fn(addr, ifsr | FSR_LNX_PF, regs)) - return; - - printk(KERN_ALERT "Unhandled prefetch abort: %s (0x%03x) at 0x%08lx\n", - inf->name, ifsr, addr); - - uc32_notify_die("", regs, inf->sig, inf->code, (void __user *)addr, - ifsr, 0); -} diff --git a/arch/unicore32/mm/flush.c b/arch/unicore32/mm/flush.c deleted file mode 100644 index 65954f8d89a2..000000000000 --- a/arch/unicore32/mm/flush.c +++ /dev/null @@ -1,94 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * linux/arch/unicore32/mm/flush.c - * - * Code specific to PKUnity SoC and UniCore ISA - * - * Copyright (C) 2001-2010 GUAN Xue-tao - */ -#include <linux/module.h> -#include <linux/mm.h> -#include <linux/pagemap.h> - -#include <asm/cacheflush.h> -#include <asm/tlbflush.h> - -void flush_cache_mm(struct mm_struct *mm) -{ -} - -void flush_cache_range(struct vm_area_struct *vma, unsigned long start, - unsigned long end) -{ - if (vma->vm_flags & VM_EXEC) - __flush_icache_all(); -} - -void flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr, - unsigned long pfn) -{ -} - -static void flush_ptrace_access(struct vm_area_struct *vma, struct page *page, - unsigned long uaddr, void *kaddr, unsigned long len) -{ - /* VIPT non-aliasing D-cache */ - if (vma->vm_flags & VM_EXEC) { - unsigned long addr = (unsigned long)kaddr; - - __cpuc_coherent_kern_range(addr, addr + len); - } -} - -/* - * Copy user data from/to a page which is mapped into a different - * processes address space. Really, we want to allow our "user - * space" model to handle this. - * - * Note that this code needs to run on the current CPU. - */ -void copy_to_user_page(struct vm_area_struct *vma, struct page *page, - unsigned long uaddr, void *dst, const void *src, - unsigned long len) -{ - memcpy(dst, src, len); - flush_ptrace_access(vma, page, uaddr, dst, len); -} - -void __flush_dcache_page(struct address_space *mapping, struct page *page) -{ - /* - * Writeback any data associated with the kernel mapping of this - * page. This ensures that data in the physical page is mutually - * coherent with the kernels mapping. - */ - __cpuc_flush_kern_dcache_area(page_address(page), PAGE_SIZE); -} - -/* - * Ensure cache coherency between kernel mapping and userspace mapping - * of this page. - */ -void flush_dcache_page(struct page *page) -{ - struct address_space *mapping; - - /* - * The zero page is never written to, so never has any dirty - * cache lines, and therefore never needs to be flushed. - */ - if (page == ZERO_PAGE(0)) - return; - - mapping = page_mapping_file(page); - - if (mapping && !mapping_mapped(mapping)) - clear_bit(PG_dcache_clean, &page->flags); - else { - __flush_dcache_page(mapping, page); - if (mapping) - __flush_icache_all(); - set_bit(PG_dcache_clean, &page->flags); - } -} -EXPORT_SYMBOL(flush_dcache_page); diff --git a/arch/unicore32/mm/init.c b/arch/unicore32/mm/init.c deleted file mode 100644 index 52425d383cea..000000000000 --- a/arch/unicore32/mm/init.c +++ /dev/null @@ -1,261 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * linux/arch/unicore32/mm/init.c - * - * Copyright (C) 2010 GUAN Xue-tao - */ -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/swap.h> -#include <linux/init.h> -#include <linux/memblock.h> -#include <linux/mman.h> -#include <linux/nodemask.h> -#include <linux/initrd.h> -#include <linux/highmem.h> -#include <linux/gfp.h> -#include <linux/sort.h> -#include <linux/dma-mapping.h> -#include <linux/export.h> - -#include <asm/sections.h> -#include <asm/setup.h> -#include <linux/sizes.h> -#include <asm/tlb.h> -#include <asm/memblock.h> -#include <mach/map.h> - -#include "mm.h" - -/* - * This keeps memory configuration data used by a couple memory - * initialization functions, as well as show_mem() for the skipping - * of holes in the memory map. It is populated by uc32_add_memory(). - */ -struct meminfo meminfo; - -static void __init find_limits(unsigned long *min, unsigned long *max_low, - unsigned long *max_high) -{ - struct meminfo *mi = &meminfo; - int i; - - *min = -1UL; - *max_low = *max_high = 0; - - for_each_bank(i, mi) { - struct membank *bank = &mi->bank[i]; - unsigned long start, end; - - start = bank_pfn_start(bank); - end = bank_pfn_end(bank); - - if (*min > start) - *min = start; - if (*max_high < end) - *max_high = end; - if (bank->highmem) - continue; - if (*max_low < end) - *max_low = end; - } -} - -static void __init uc32_bootmem_free(unsigned long max_low) -{ - unsigned long max_zone_pfn[MAX_NR_ZONES] = { 0 }; - - max_zone_pfn[ZONE_DMA] = max_low; - max_zone_pfn[ZONE_NORMAL] = max_low; - - /* - * Adjust the sizes according to any special requirements for - * this machine type. - * This might lower ZONE_DMA limit. - */ - arch_adjust_zones(max_zone_pfn); - - free_area_init(max_zone_pfn); -} - -int pfn_valid(unsigned long pfn) -{ - return memblock_is_memory(pfn << PAGE_SHIFT); -} -EXPORT_SYMBOL(pfn_valid); - -static void uc32_memory_present(void) -{ -} - -static int __init meminfo_cmp(const void *_a, const void *_b) -{ - const struct membank *a = _a, *b = _b; - long cmp = bank_pfn_start(a) - bank_pfn_start(b); - return cmp < 0 ? -1 : cmp > 0 ? 1 : 0; -} - -void __init uc32_memblock_init(struct meminfo *mi) -{ - int i; - - sort(&meminfo.bank, meminfo.nr_banks, sizeof(meminfo.bank[0]), - meminfo_cmp, NULL); - - for (i = 0; i < mi->nr_banks; i++) - memblock_add(mi->bank[i].start, mi->bank[i].size); - - /* Register the kernel text, kernel data and initrd with memblock. */ - memblock_reserve(__pa(_text), _end - _text); - -#ifdef CONFIG_BLK_DEV_INITRD - if (!phys_initrd_size) { - phys_initrd_start = 0x01000000; - phys_initrd_size = SZ_8M; - } - - if (phys_initrd_size) { - memblock_reserve(phys_initrd_start, phys_initrd_size); - - /* Now convert initrd to virtual addresses */ - initrd_start = __phys_to_virt(phys_initrd_start); - initrd_end = initrd_start + phys_initrd_size; - } -#endif - - uc32_mm_memblock_reserve(); - - memblock_allow_resize(); - memblock_dump_all(); -} - -void __init bootmem_init(void) -{ - unsigned long min, max_low, max_high; - - max_low = max_high = 0; - - find_limits(&min, &max_low, &max_high); - - node_set_online(0); - - /* - * Sparsemem tries to allocate bootmem in memory_present(), - * so must be done after the fixed reservations - */ - uc32_memory_present(); - - /* - * sparse_init() needs the bootmem allocator up and running. - */ - sparse_init(); - - /* - * Now free the memory - free_area_init needs - * the sparse mem_map arrays initialized by sparse_init() - * for memmap_init_zone(), otherwise all PFNs are invalid. - */ - uc32_bootmem_free(max_low); - - high_memory = __va((max_low << PAGE_SHIFT) - 1) + 1; - - /* - * This doesn't seem to be used by the Linux memory manager any - * more, but is used by ll_rw_block. If we can get rid of it, we - * also get rid of some of the stuff above as well. - * - * Note: max_low_pfn and max_pfn reflect the number of _pages_ in - * the system, not the maximum PFN. - */ - max_low_pfn = max_low - PHYS_PFN_OFFSET; - max_pfn = max_high - PHYS_PFN_OFFSET; -} - -static inline void -free_memmap(unsigned long start_pfn, unsigned long end_pfn) -{ - struct page *start_pg, *end_pg; - unsigned long pg, pgend; - - /* - * Convert start_pfn/end_pfn to a struct page pointer. - */ - start_pg = pfn_to_page(start_pfn - 1) + 1; - end_pg = pfn_to_page(end_pfn); - - /* - * Convert to physical addresses, and - * round start upwards and end downwards. - */ - pg = PAGE_ALIGN(__pa(start_pg)); - pgend = __pa(end_pg) & PAGE_MASK; - - /* - * If there are free pages between these, - * free the section of the memmap array. - */ - if (pg < pgend) - memblock_free(pg, pgend - pg); -} - -/* - * The mem_map array can get very big. Free the unused area of the memory map. - */ -static void __init free_unused_memmap(struct meminfo *mi) -{ - unsigned long bank_start, prev_bank_end = 0; - unsigned int i; - - /* - * This relies on each bank being in address order. - * The banks are sorted previously in bootmem_init(). - */ - for_each_bank(i, mi) { - struct membank *bank = &mi->bank[i]; - - bank_start = bank_pfn_start(bank); - - /* - * If we had a previous bank, and there is a space - * between the current bank and the previous, free it. - */ - if (prev_bank_end && prev_bank_end < bank_start) - free_memmap(prev_bank_end, bank_start); - - /* - * Align up here since the VM subsystem insists that the - * memmap entries are valid from the bank end aligned to - * MAX_ORDER_NR_PAGES. - */ - prev_bank_end = ALIGN(bank_pfn_end(bank), MAX_ORDER_NR_PAGES); - } -} - -/* - * mem_init() marks the free areas in the mem_map and tells us how much - * memory is free. This is done after various parts of the system have - * claimed their memory after the kernel image. - */ -void __init mem_init(void) -{ - max_mapnr = pfn_to_page(max_pfn + PHYS_PFN_OFFSET) - mem_map; - - free_unused_memmap(&meminfo); - - /* this will put all unused low memory onto the freelists */ - memblock_free_all(); - - mem_init_print_info(NULL); - - BUILD_BUG_ON(TASK_SIZE > MODULES_VADDR); - BUG_ON(TASK_SIZE > MODULES_VADDR); - - if (PAGE_SIZE >= 16384 && get_num_physpages() <= 128) { - /* - * On a machine this small we won't get - * anywhere without overcommit, so turn - * it on by default. - */ - sysctl_overcommit_memory = OVERCOMMIT_ALWAYS; - } -} diff --git a/arch/unicore32/mm/ioremap.c b/arch/unicore32/mm/ioremap.c deleted file mode 100644 index 46a64bd6156a..000000000000 --- a/arch/unicore32/mm/ioremap.c +++ /dev/null @@ -1,242 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * linux/arch/unicore32/mm/ioremap.c - * - * Code specific to PKUnity SoC and UniCore ISA - * - * Copyright (C) 2001-2010 GUAN Xue-tao - * - * Re-map IO memory to kernel address space so that we can access it. - * - * This allows a driver to remap an arbitrary region of bus memory into - * virtual space. One should *only* use readl, writel, memcpy_toio and - * so on with such remapped areas. - * - * Because UniCore only has a 32-bit address space we can't address the - * whole of the (physical) PCI space at once. PCI huge-mode addressing - * allows us to circumvent this restriction by splitting PCI space into - * two 2GB chunks and mapping only one at a time into processor memory. - * We use MMU protection domains to trap any attempt to access the bank - * that is not currently mapped. (This isn't fully implemented yet.) - */ -#include <linux/module.h> -#include <linux/errno.h> -#include <linux/mm.h> -#include <linux/vmalloc.h> -#include <linux/io.h> - -#include <asm/cputype.h> -#include <asm/cacheflush.h> -#include <asm/mmu_context.h> -#include <asm/pgalloc.h> -#include <asm/tlbflush.h> -#include <linux/sizes.h> - -#include <mach/map.h> -#include "mm.h" - -/* - * Used by ioremap() and iounmap() code to mark (super)section-mapped - * I/O regions in vm_struct->flags field. - */ -#define VM_UNICORE_SECTION_MAPPING 0x80000000 - -int ioremap_page(unsigned long virt, unsigned long phys, - const struct mem_type *mtype) -{ - return ioremap_page_range(virt, virt + PAGE_SIZE, phys, - __pgprot(mtype->prot_pte)); -} -EXPORT_SYMBOL(ioremap_page); - -/* - * Section support is unsafe on SMP - If you iounmap and ioremap a region, - * the other CPUs will not see this change until their next context switch. - * Meanwhile, (eg) if an interrupt comes in on one of those other CPUs - * which requires the new ioremap'd region to be referenced, the CPU will - * reference the _old_ region. - * - * Note that get_vm_area_caller() allocates a guard 4K page, so we need to - * mask the size back to 4MB aligned or we will overflow in the loop below. - */ -static void unmap_area_sections(unsigned long virt, unsigned long size) -{ - unsigned long addr = virt, end = virt + (size & ~(SZ_4M - 1)); - pgd_t *pgd; - - flush_cache_vunmap(addr, end); - pgd = pgd_offset_k(addr); - do { - pmd_t pmd, *pmdp = pmd_offset((pud_t *)pgd, addr); - - pmd = *pmdp; - if (!pmd_none(pmd)) { - /* - * Clear the PMD from the page table, and - * increment the kvm sequence so others - * notice this change. - * - * Note: this is still racy on SMP machines. - */ - pmd_clear(pmdp); - - /* - * Free the page table, if there was one. - */ - if ((pmd_val(pmd) & PMD_TYPE_MASK) == PMD_TYPE_TABLE) - pte_free_kernel(&init_mm, pmd_page_vaddr(pmd)); - } - - addr += PGDIR_SIZE; - pgd++; - } while (addr < end); - - flush_tlb_kernel_range(virt, end); -} - -static int -remap_area_sections(unsigned long virt, unsigned long pfn, - size_t size, const struct mem_type *type) -{ - unsigned long addr = virt, end = virt + size; - pgd_t *pgd; - - /* - * Remove and free any PTE-based mapping, and - * sync the current kernel mapping. - */ - unmap_area_sections(virt, size); - - pgd = pgd_offset_k(addr); - do { - pmd_t *pmd = pmd_offset((pud_t *)pgd, addr); - - set_pmd(pmd, __pmd(__pfn_to_phys(pfn) | type->prot_sect)); - pfn += SZ_4M >> PAGE_SHIFT; - flush_pmd_entry(pmd); - - addr += PGDIR_SIZE; - pgd++; - } while (addr < end); - - return 0; -} - -void __iomem *__uc32_ioremap_pfn_caller(unsigned long pfn, - unsigned long offset, size_t size, unsigned int mtype, void *caller) -{ - const struct mem_type *type; - int err; - unsigned long addr; - struct vm_struct *area; - - /* - * High mappings must be section aligned - */ - if (pfn >= 0x100000 && (__pfn_to_phys(pfn) & ~SECTION_MASK)) - return NULL; - - /* - * Don't allow RAM to be mapped - */ - if (pfn_valid(pfn)) { - WARN(1, "BUG: Your driver calls ioremap() on\n" - "system memory. This leads to architecturally\n" - "unpredictable behaviour, and ioremap() will fail in\n" - "the next kernel release. Please fix your driver.\n"); - return NULL; - } - - type = get_mem_type(mtype); - if (!type) - return NULL; - - /* - * Page align the mapping size, taking account of any offset. - */ - size = PAGE_ALIGN(offset + size); - - area = get_vm_area_caller(size, VM_IOREMAP, caller); - if (!area) - return NULL; - addr = (unsigned long)area->addr; - - if (!((__pfn_to_phys(pfn) | size | addr) & ~PMD_MASK)) { - area->flags |= VM_UNICORE_SECTION_MAPPING; - err = remap_area_sections(addr, pfn, size, type); - } else - err = ioremap_page_range(addr, addr + size, __pfn_to_phys(pfn), - __pgprot(type->prot_pte)); - - if (err) { - vunmap((void *)addr); - return NULL; - } - - flush_cache_vmap(addr, addr + size); - return (void __iomem *) (offset + addr); -} - -void __iomem *__uc32_ioremap_caller(unsigned long phys_addr, size_t size, - unsigned int mtype, void *caller) -{ - unsigned long last_addr; - unsigned long offset = phys_addr & ~PAGE_MASK; - unsigned long pfn = __phys_to_pfn(phys_addr); - - /* - * Don't allow wraparound or zero size - */ - last_addr = phys_addr + size - 1; - if (!size || last_addr < phys_addr) - return NULL; - - return __uc32_ioremap_pfn_caller(pfn, offset, size, mtype, caller); -} - -/* - * Remap an arbitrary physical address space into the kernel virtual - * address space. Needed when the kernel wants to access high addresses - * directly. - * - * NOTE! We need to allow non-page-aligned mappings too: we will obviously - * have to convert them into an offset in a page-aligned mapping, but the - * caller shouldn't need to know that small detail. - */ -void __iomem * -__uc32_ioremap_pfn(unsigned long pfn, unsigned long offset, size_t size, - unsigned int mtype) -{ - return __uc32_ioremap_pfn_caller(pfn, offset, size, mtype, - __builtin_return_address(0)); -} -EXPORT_SYMBOL(__uc32_ioremap_pfn); - -void __iomem * -__uc32_ioremap(unsigned long phys_addr, size_t size) -{ - return __uc32_ioremap_caller(phys_addr, size, MT_DEVICE, - __builtin_return_address(0)); -} -EXPORT_SYMBOL(__uc32_ioremap); - -void __uc32_iounmap(volatile void __iomem *io_addr) -{ - void *addr = (void *)(PAGE_MASK & (unsigned long)io_addr); - struct vm_struct *vm; - - /* - * If this is a section based mapping we need to handle it - * specially as the VM subsystem does not know how to handle - * such a beast. We need the lock here b/c we need to clear - * all the mappings before the area can be reclaimed - * by someone else. - */ - vm = find_vm_area(addr); - if (vm && (vm->flags & VM_IOREMAP) && - (vm->flags & VM_UNICORE_SECTION_MAPPING)) - unmap_area_sections((unsigned long)vm->addr, vm->size); - - vunmap(addr); -} -EXPORT_SYMBOL(__uc32_iounmap); diff --git a/arch/unicore32/mm/mm.h b/arch/unicore32/mm/mm.h deleted file mode 100644 index f157f5d249ab..000000000000 --- a/arch/unicore32/mm/mm.h +++ /dev/null @@ -1,31 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * linux/arch/unicore32/mm/mm.h - * - * Code specific to PKUnity SoC and UniCore ISA - * - * Copyright (C) 2001-2010 GUAN Xue-tao - */ -#include <asm/hwdef-copro.h> - -/* the upper-most page table pointer */ -extern pmd_t *top_pmd; -extern int sysctl_overcommit_memory; - -#define TOP_PTE(x) pte_offset_kernel(top_pmd, x) - -struct mem_type { - unsigned int prot_pte; - unsigned int prot_l1; - unsigned int prot_sect; -}; - -const struct mem_type *get_mem_type(unsigned int type); - -extern void __flush_dcache_page(struct address_space *, struct page *); -extern void hook_fault_code(int nr, int (*fn) - (unsigned long, unsigned int, struct pt_regs *), - int sig, int code, const char *name); - -void __init bootmem_init(void); -void uc32_mm_memblock_reserve(void); diff --git a/arch/unicore32/mm/mmu.c b/arch/unicore32/mm/mmu.c deleted file mode 100644 index 183d5b056814..000000000000 --- a/arch/unicore32/mm/mmu.c +++ /dev/null @@ -1,513 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * linux/arch/unicore32/mm/mmu.c - * - * Code specific to PKUnity SoC and UniCore ISA - * - * Copyright (C) 2001-2010 GUAN Xue-tao - */ -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/mman.h> -#include <linux/nodemask.h> -#include <linux/memblock.h> -#include <linux/fs.h> -#include <linux/io.h> - -#include <asm/cputype.h> -#include <asm/sections.h> -#include <asm/setup.h> -#include <linux/sizes.h> -#include <asm/tlb.h> -#include <asm/memblock.h> - -#include <mach/map.h> - -#include "mm.h" - -/* - * empty_zero_page is a special page that is used for - * zero-initialized data and COW. - */ -struct page *empty_zero_page; -EXPORT_SYMBOL(empty_zero_page); - -/* - * The pmd table for the upper-most set of pages. - */ -pmd_t *top_pmd; - -pgprot_t pgprot_user; -EXPORT_SYMBOL(pgprot_user); - -pgprot_t pgprot_kernel; -EXPORT_SYMBOL(pgprot_kernel); - -static int __init noalign_setup(char *__unused) -{ - cr_alignment &= ~CR_A; - cr_no_alignment &= ~CR_A; - set_cr(cr_alignment); - return 1; -} -__setup("noalign", noalign_setup); - -void adjust_cr(unsigned long mask, unsigned long set) -{ - unsigned long flags; - - mask &= ~CR_A; - - set &= mask; - - local_irq_save(flags); - - cr_no_alignment = (cr_no_alignment & ~mask) | set; - cr_alignment = (cr_alignment & ~mask) | set; - - set_cr((get_cr() & ~mask) | set); - - local_irq_restore(flags); -} - -struct map_desc { - unsigned long virtual; - unsigned long pfn; - unsigned long length; - unsigned int type; -}; - -#define PROT_PTE_DEVICE (PTE_PRESENT | PTE_YOUNG | \ - PTE_DIRTY | PTE_READ | PTE_WRITE) -#define PROT_SECT_DEVICE (PMD_TYPE_SECT | PMD_PRESENT | \ - PMD_SECT_READ | PMD_SECT_WRITE) - -static struct mem_type mem_types[] = { - [MT_DEVICE] = { /* Strongly ordered */ - .prot_pte = PROT_PTE_DEVICE, - .prot_l1 = PMD_TYPE_TABLE | PMD_PRESENT, - .prot_sect = PROT_SECT_DEVICE, - }, - /* - * MT_KUSER: pte for vecpage -- cacheable, - * and sect for unigfx mmap -- noncacheable - */ - [MT_KUSER] = { - .prot_pte = PTE_PRESENT | PTE_YOUNG | PTE_DIRTY | - PTE_CACHEABLE | PTE_READ | PTE_EXEC, - .prot_l1 = PMD_TYPE_TABLE | PMD_PRESENT, - .prot_sect = PROT_SECT_DEVICE, - }, - [MT_HIGH_VECTORS] = { - .prot_pte = PTE_PRESENT | PTE_YOUNG | PTE_DIRTY | - PTE_CACHEABLE | PTE_READ | PTE_WRITE | - PTE_EXEC, - .prot_l1 = PMD_TYPE_TABLE | PMD_PRESENT, - }, - [MT_MEMORY] = { - .prot_pte = PTE_PRESENT | PTE_YOUNG | PTE_DIRTY | - PTE_WRITE | PTE_EXEC, - .prot_l1 = PMD_TYPE_TABLE | PMD_PRESENT, - .prot_sect = PMD_TYPE_SECT | PMD_PRESENT | PMD_SECT_CACHEABLE | - PMD_SECT_READ | PMD_SECT_WRITE | PMD_SECT_EXEC, - }, - [MT_ROM] = { - .prot_sect = PMD_TYPE_SECT | PMD_PRESENT | PMD_SECT_CACHEABLE | - PMD_SECT_READ, - }, -}; - -const struct mem_type *get_mem_type(unsigned int type) -{ - return type < ARRAY_SIZE(mem_types) ? &mem_types[type] : NULL; -} -EXPORT_SYMBOL(get_mem_type); - -/* - * Adjust the PMD section entries according to the CPU in use. - */ -static void __init build_mem_type_table(void) -{ - pgprot_user = __pgprot(PTE_PRESENT | PTE_YOUNG | PTE_CACHEABLE); - pgprot_kernel = __pgprot(PTE_PRESENT | PTE_YOUNG | - PTE_DIRTY | PTE_READ | PTE_WRITE | - PTE_EXEC | PTE_CACHEABLE); -} - -#define vectors_base() (vectors_high() ? 0xffff0000 : 0) - -static pte_t * __init early_pte_alloc(pmd_t *pmd, unsigned long addr, - unsigned long prot) -{ - if (pmd_none(*pmd)) { - size_t size = PTRS_PER_PTE * sizeof(pte_t); - pte_t *pte = memblock_alloc(size, size); - - if (!pte) - panic("%s: Failed to allocate %zu bytes align=%zx\n", - __func__, size, size); - - __pmd_populate(pmd, __pa(pte) | prot); - } - BUG_ON(pmd_bad(*pmd)); - return pte_offset_kernel(pmd, addr); -} - -static void __init alloc_init_pte(pmd_t *pmd, unsigned long addr, - unsigned long end, unsigned long pfn, - const struct mem_type *type) -{ - pte_t *pte = early_pte_alloc(pmd, addr, type->prot_l1); - do { - set_pte(pte, pfn_pte(pfn, __pgprot(type->prot_pte))); - pfn++; - } while (pte++, addr += PAGE_SIZE, addr != end); -} - -static void __init alloc_init_section(pgd_t *pgd, unsigned long addr, - unsigned long end, unsigned long phys, - const struct mem_type *type) -{ - pmd_t *pmd = pmd_offset((pud_t *)pgd, addr); - - /* - * Try a section mapping - end, addr and phys must all be aligned - * to a section boundary. - */ - if (((addr | end | phys) & ~SECTION_MASK) == 0) { - pmd_t *p = pmd; - - do { - set_pmd(pmd, __pmd(phys | type->prot_sect)); - phys += SECTION_SIZE; - } while (pmd++, addr += SECTION_SIZE, addr != end); - - flush_pmd_entry(p); - } else { - /* - * No need to loop; pte's aren't interested in the - * individual L1 entries. - */ - alloc_init_pte(pmd, addr, end, __phys_to_pfn(phys), type); - } -} - -/* - * Create the page directory entries and any necessary - * page tables for the mapping specified by `md'. We - * are able to cope here with varying sizes and address - * offsets, and we take full advantage of sections. - */ -static void __init create_mapping(struct map_desc *md) -{ - unsigned long phys, addr, length, end; - const struct mem_type *type; - pgd_t *pgd; - - if (md->virtual != vectors_base() && md->virtual < TASK_SIZE) { - printk(KERN_WARNING "BUG: not creating mapping for " - "0x%08llx at 0x%08lx in user region\n", - __pfn_to_phys((u64)md->pfn), md->virtual); - return; - } - - if ((md->type == MT_DEVICE || md->type == MT_ROM) && - md->virtual >= PAGE_OFFSET && md->virtual < VMALLOC_END) { - printk(KERN_WARNING "BUG: mapping for 0x%08llx at 0x%08lx " - "overlaps vmalloc space\n", - __pfn_to_phys((u64)md->pfn), md->virtual); - } - - type = &mem_types[md->type]; - - addr = md->virtual & PAGE_MASK; - phys = (unsigned long)__pfn_to_phys(md->pfn); - length = PAGE_ALIGN(md->length + (md->virtual & ~PAGE_MASK)); - - if (type->prot_l1 == 0 && ((addr | phys | length) & ~SECTION_MASK)) { - printk(KERN_WARNING "BUG: map for 0x%08lx at 0x%08lx can not " - "be mapped using pages, ignoring.\n", - __pfn_to_phys(md->pfn), addr); - return; - } - - pgd = pgd_offset_k(addr); - end = addr + length; - do { - unsigned long next = pgd_addr_end(addr, end); - - alloc_init_section(pgd, addr, next, phys, type); - - phys += next - addr; - addr = next; - } while (pgd++, addr != end); -} - -static void * __initdata vmalloc_min = (void *)(VMALLOC_END - SZ_128M); - -/* - * vmalloc=size forces the vmalloc area to be exactly 'size' - * bytes. This can be used to increase (or decrease) the vmalloc - * area - the default is 128m. - */ -static int __init early_vmalloc(char *arg) -{ - unsigned long vmalloc_reserve = memparse(arg, NULL); - - if (vmalloc_reserve < SZ_16M) { - vmalloc_reserve = SZ_16M; - printk(KERN_WARNING - "vmalloc area too small, limiting to %luMB\n", - vmalloc_reserve >> 20); - } - - if (vmalloc_reserve > VMALLOC_END - (PAGE_OFFSET + SZ_32M)) { - vmalloc_reserve = VMALLOC_END - (PAGE_OFFSET + SZ_32M); - printk(KERN_WARNING - "vmalloc area is too big, limiting to %luMB\n", - vmalloc_reserve >> 20); - } - - vmalloc_min = (void *)(VMALLOC_END - vmalloc_reserve); - return 0; -} -early_param("vmalloc", early_vmalloc); - -static phys_addr_t lowmem_limit __initdata = SZ_1G; - -static void __init sanity_check_meminfo(void) -{ - int i, j; - - lowmem_limit = __pa(vmalloc_min - 1) + 1; - memblock_set_current_limit(lowmem_limit); - - for (i = 0, j = 0; i < meminfo.nr_banks; i++) { - struct membank *bank = &meminfo.bank[j]; - *bank = meminfo.bank[i]; - j++; - } - meminfo.nr_banks = j; -} - -static inline void prepare_page_table(void) -{ - unsigned long addr; - phys_addr_t end; - - /* - * Clear out all the mappings below the kernel image. - */ - for (addr = 0; addr < MODULES_VADDR; addr += PGDIR_SIZE) - pmd_clear(pmd_off_k(addr)); - - for ( ; addr < PAGE_OFFSET; addr += PGDIR_SIZE) - pmd_clear(pmd_off_k(addr)); - - /* - * Find the end of the first block of lowmem. - */ - end = memblock.memory.regions[0].base + memblock.memory.regions[0].size; - if (end >= lowmem_limit) - end = lowmem_limit; - - /* - * Clear out all the kernel space mappings, except for the first - * memory bank, up to the end of the vmalloc region. - */ - for (addr = __phys_to_virt(end); - addr < VMALLOC_END; addr += PGDIR_SIZE) - pmd_clear(pmd_off_k(addr)); -} - -/* - * Reserve the special regions of memory - */ -void __init uc32_mm_memblock_reserve(void) -{ - /* - * Reserve the page tables. These are already in use, - * and can only be in node 0. - */ - memblock_reserve(__pa(swapper_pg_dir), PTRS_PER_PGD * sizeof(pgd_t)); -} - -/* - * Set up device the mappings. Since we clear out the page tables for all - * mappings above VMALLOC_END, we will remove any debug device mappings. - * This means you have to be careful how you debug this function, or any - * called function. This means you can't use any function or debugging - * method which may touch any device, otherwise the kernel _will_ crash. - */ -static void __init devicemaps_init(void) -{ - struct map_desc map; - unsigned long addr; - void *vectors; - - /* - * Allocate the vector page early. - */ - vectors = memblock_alloc(PAGE_SIZE, PAGE_SIZE); - if (!vectors) - panic("%s: Failed to allocate %lu bytes align=0x%lx\n", - __func__, PAGE_SIZE, PAGE_SIZE); - - for (addr = VMALLOC_END; addr; addr += PGDIR_SIZE) - pmd_clear(pmd_off_k(addr)); - - /* - * Create a mapping for the machine vectors at the high-vectors - * location (0xffff0000). If we aren't using high-vectors, also - * create a mapping at the low-vectors virtual address. - */ - map.pfn = __phys_to_pfn(virt_to_phys(vectors)); - map.virtual = VECTORS_BASE; - map.length = PAGE_SIZE; - map.type = MT_HIGH_VECTORS; - create_mapping(&map); - - /* - * Create a mapping for the kuser page at the special - * location (0xbfff0000) to the same vectors location. - */ - map.pfn = __phys_to_pfn(virt_to_phys(vectors)); - map.virtual = KUSER_VECPAGE_BASE; - map.length = PAGE_SIZE; - map.type = MT_KUSER; - create_mapping(&map); - - /* - * Finally flush the caches and tlb to ensure that we're in a - * consistent state wrt the writebuffer. This also ensures that - * any write-allocated cache lines in the vector page are written - * back. After this point, we can start to touch devices again. - */ - local_flush_tlb_all(); - flush_cache_all(); -} - -static void __init map_lowmem(void) -{ - struct memblock_region *reg; - - /* Map all the lowmem memory banks. */ - for_each_memblock(memory, reg) { - phys_addr_t start = reg->base; - phys_addr_t end = start + reg->size; - struct map_desc map; - - if (end > lowmem_limit) - end = lowmem_limit; - if (start >= end) - break; - - map.pfn = __phys_to_pfn(start); - map.virtual = __phys_to_virt(start); - map.length = end - start; - map.type = MT_MEMORY; - - create_mapping(&map); - } -} - -/* - * paging_init() sets up the page tables, initialises the zone memory - * maps, and sets up the zero page, bad page and bad page tables. - */ -void __init paging_init(void) -{ - void *zero_page; - - build_mem_type_table(); - sanity_check_meminfo(); - prepare_page_table(); - map_lowmem(); - devicemaps_init(); - - top_pmd = pmd_off_k(0xffff0000); - - /* allocate the zero page. */ - zero_page = memblock_alloc(PAGE_SIZE, PAGE_SIZE); - if (!zero_page) - panic("%s: Failed to allocate %lu bytes align=0x%lx\n", - __func__, PAGE_SIZE, PAGE_SIZE); - - bootmem_init(); - - empty_zero_page = virt_to_page(zero_page); - __flush_dcache_page(NULL, empty_zero_page); -} - -/* - * In order to soft-boot, we need to insert a 1:1 mapping in place of - * the user-mode pages. This will then ensure that we have predictable - * results when turning the mmu off - */ -void setup_mm_for_reboot(void) -{ - unsigned long base_pmdval; - pgd_t *pgd; - int i; - - /* - * We need to access to user-mode page tables here. For kernel threads - * we don't have any user-mode mappings so we use the context that we - * "borrowed". - */ - pgd = current->active_mm->pgd; - - base_pmdval = PMD_SECT_WRITE | PMD_SECT_READ | PMD_TYPE_SECT; - - for (i = 0; i < FIRST_USER_PGD_NR + USER_PTRS_PER_PGD; i++, pgd++) { - unsigned long pmdval = (i << PGDIR_SHIFT) | base_pmdval; - pmd_t *pmd; - - pmd = pmd_off(pgd, i << PGDIR_SHIFT); - set_pmd(pmd, __pmd(pmdval)); - flush_pmd_entry(pmd); - } - - local_flush_tlb_all(); -} - -/* - * Take care of architecture specific things when placing a new PTE into - * a page table, or changing an existing PTE. Basically, there are two - * things that we need to take care of: - * - * 1. If PG_dcache_clean is not set for the page, we need to ensure - * that any cache entries for the kernels virtual memory - * range are written back to the page. - * 2. If we have multiple shared mappings of the same space in - * an object, we need to deal with the cache aliasing issues. - * - * Note that the pte lock will be held. - */ -void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, - pte_t *ptep) -{ - unsigned long pfn = pte_pfn(*ptep); - struct address_space *mapping; - struct page *page; - - if (!pfn_valid(pfn)) - return; - - /* - * The zero page is never written to, so never has any dirty - * cache lines, and therefore never needs to be flushed. - */ - page = pfn_to_page(pfn); - if (page == ZERO_PAGE(0)) - return; - - mapping = page_mapping_file(page); - if (!test_and_set_bit(PG_dcache_clean, &page->flags)) - __flush_dcache_page(mapping, page); - if (mapping) - if (vma->vm_flags & VM_EXEC) - __flush_icache_all(); -} diff --git a/arch/unicore32/mm/pgd.c b/arch/unicore32/mm/pgd.c deleted file mode 100644 index f01c73e04836..000000000000 --- a/arch/unicore32/mm/pgd.c +++ /dev/null @@ -1,102 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * linux/arch/unicore32/mm/pgd.c - * - * Code specific to PKUnity SoC and UniCore ISA - * - * Copyright (C) 2001-2010 GUAN Xue-tao - */ -#include <linux/mm.h> -#include <linux/gfp.h> -#include <linux/highmem.h> - -#include <asm/pgalloc.h> -#include <asm/page.h> -#include <asm/tlbflush.h> - -#include "mm.h" - -#define FIRST_KERNEL_PGD_NR (FIRST_USER_PGD_NR + USER_PTRS_PER_PGD) - -/* - * need to get a 4k page for level 1 - */ -pgd_t *get_pgd_slow(struct mm_struct *mm) -{ - pgd_t *new_pgd, *init_pgd; - pmd_t *new_pmd, *init_pmd; - pte_t *new_pte, *init_pte; - - new_pgd = (pgd_t *)__get_free_pages(GFP_KERNEL, 0); - if (!new_pgd) - goto no_pgd; - - memset(new_pgd, 0, FIRST_KERNEL_PGD_NR * sizeof(pgd_t)); - - /* - * Copy over the kernel and IO PGD entries - */ - init_pgd = pgd_offset_k(0); - memcpy(new_pgd + FIRST_KERNEL_PGD_NR, init_pgd + FIRST_KERNEL_PGD_NR, - (PTRS_PER_PGD - FIRST_KERNEL_PGD_NR) * sizeof(pgd_t)); - - clean_dcache_area(new_pgd, PTRS_PER_PGD * sizeof(pgd_t)); - - if (!vectors_high()) { - /* - * On UniCore, first page must always be allocated since it - * contains the machine vectors. - */ - new_pmd = pmd_alloc(mm, (pud_t *)new_pgd, 0); - if (!new_pmd) - goto no_pmd; - - new_pte = pte_alloc_map(mm, new_pmd, 0); - if (!new_pte) - goto no_pte; - - init_pmd = pmd_offset((pud_t *)init_pgd, 0); - init_pte = pte_offset_map(init_pmd, 0); - set_pte(new_pte, *init_pte); - pte_unmap(init_pte); - pte_unmap(new_pte); - } - - return new_pgd; - -no_pte: - pmd_free(mm, new_pmd); - mm_dec_nr_pmds(mm); -no_pmd: - free_pages((unsigned long)new_pgd, 0); -no_pgd: - return NULL; -} - -void free_pgd_slow(struct mm_struct *mm, pgd_t *pgd) -{ - pmd_t *pmd; - pgtable_t pte; - - if (!pgd) - return; - - /* pgd is always present and good */ - pmd = pmd_off(pgd, 0); - if (pmd_none(*pmd)) - goto free; - if (pmd_bad(*pmd)) { - pmd_ERROR(*pmd); - pmd_clear(pmd); - goto free; - } - - pte = pmd_pgtable(*pmd); - pmd_clear(pmd); - pte_free(mm, pte); - mm_dec_nr_ptes(mm); - pmd_free(mm, pmd); - mm_dec_nr_pmds(mm); -free: - free_pages((unsigned long) pgd, 0); -} diff --git a/arch/unicore32/mm/proc-macros.S b/arch/unicore32/mm/proc-macros.S deleted file mode 100644 index 3b0ae7d5bd80..000000000000 --- a/arch/unicore32/mm/proc-macros.S +++ /dev/null @@ -1,142 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * linux/arch/unicore32/mm/proc-macros.S - * - * Code specific to PKUnity SoC and UniCore ISA - * - * Copyright (C) 2001-2010 GUAN Xue-tao - * - * We need constants.h for: - * VMA_VM_MM - * VMA_VM_FLAGS - * VM_EXEC - */ -#include <generated/asm-offsets.h> -#include <asm/thread_info.h> -#include <asm/memory.h> - -/* - * the cache line sizes of the I and D cache are the same - */ -#define CACHE_LINESIZE 32 - -/* - * This is the maximum size of an area which will be invalidated - * using the single invalidate entry instructions. Anything larger - * than this, and we go for the whole cache. - * - * This value should be chosen such that we choose the cheapest - * alternative. - */ -#ifdef CONFIG_CPU_UCV2 -#define MAX_AREA_SIZE 0x800 /* 64 cache line */ -#endif - -/* - * vma_vm_mm - get mm pointer from vma pointer (vma->vm_mm) - */ - .macro vma_vm_mm, rd, rn - ldw \rd, [\rn+], #VMA_VM_MM - .endm - -/* - * vma_vm_flags - get vma->vm_flags - */ - .macro vma_vm_flags, rd, rn - ldw \rd, [\rn+], #VMA_VM_FLAGS - .endm - - .macro tsk_mm, rd, rn - ldw \rd, [\rn+], #TI_TASK - ldw \rd, [\rd+], #TSK_ACTIVE_MM - .endm - -/* - * act_mm - get current->active_mm - */ - .macro act_mm, rd - andn \rd, sp, #8128 - andn \rd, \rd, #63 - ldw \rd, [\rd+], #TI_TASK - ldw \rd, [\rd+], #TSK_ACTIVE_MM - .endm - -/* - * mmid - get context id from mm pointer (mm->context.id) - */ - .macro mmid, rd, rn - ldw \rd, [\rn+], #MM_CONTEXT_ID - .endm - -/* - * mask_asid - mask the ASID from the context ID - */ - .macro asid, rd, rn - and \rd, \rn, #255 - .endm - - .macro crval, clear, mmuset, ucset - .word \clear - .word \mmuset - .endm - -#ifndef CONFIG_CPU_DCACHE_LINE_DISABLE -/* - * va2pa va, pa, tbl, msk, off, err - * This macro is used to translate virtual address to its physical address. - * - * va: virtual address - * pa: physical address, result is stored in this register - * tbl, msk, off: temp registers, will be destroyed - * err: jump to error label if the physical address not exist - * NOTE: all regs must be different - */ - .macro va2pa, va, pa, tbl, msk, off, err=990f - movc \pa, p0.c2, #0 - mov \off, \va >> #22 @ off <- index of 1st page table - adr \tbl, 910f @ tbl <- table of 1st page table -900: @ ---- handle 1, 2 page table - add \pa, \pa, #PAGE_OFFSET @ pa <- virt addr of page table - ldw \pa, [\pa+], \off << #2 @ pa <- the content of pt - cand.a \pa, #4 @ test exist bit - beq \err @ if not exist - and \off, \pa, #3 @ off <- the last 2 bits - add \tbl, \tbl, \off << #3 @ cmove table pointer - ldw \msk, [\tbl+], #0 @ get the mask - ldw pc, [\tbl+], #4 -930: @ ---- handle 2nd page table - and \pa, \pa, \msk @ pa <- phys addr of 2nd pt - mov \off, \va << #10 - cntlo \tbl, \msk @ use tbl as temp reg - mov \off, \off >> \tbl - mov \off, \off >> #2 @ off <- index of 2nd pt - adr \tbl, 920f @ tbl <- table of 2nd pt - b 900b -910: @ 1st level page table - .word 0xfffff000, 930b @ second level page table - .word 0xfffffc00, 930b @ second level large page table - .word 0x00000000, \err @ invalid - .word 0xffc00000, 980f @ super page - -920: @ 2nd level page table - .word 0xfffff000, 980f @ page - .word 0xffffc000, 980f @ middle page - .word 0xffff0000, 980f @ large page - .word 0x00000000, \err @ invalid -980: - andn \tbl, \va, \msk - and \pa, \pa, \msk - or \pa, \pa, \tbl -990: - .endm -#endif - - .macro dcacheline_flush, addr, t1, t2 - mov \t1, \addr << #20 - ldw \t2, =_stext @ _stext must ALIGN(4096) - add \t2, \t2, \t1 >> #20 - ldw \t1, [\t2+], #0x0000 - ldw \t1, [\t2+], #0x1000 - ldw \t1, [\t2+], #0x2000 - ldw \t1, [\t2+], #0x3000 - .endm diff --git a/arch/unicore32/mm/proc-syms.c b/arch/unicore32/mm/proc-syms.c deleted file mode 100644 index 6c081616fc3c..000000000000 --- a/arch/unicore32/mm/proc-syms.c +++ /dev/null @@ -1,19 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * linux/arch/unicore32/mm/proc-syms.c - * - * Code specific to PKUnity SoC and UniCore ISA - * - * Copyright (C) 2001-2010 GUAN Xue-tao - */ -#include <linux/module.h> -#include <linux/mm.h> - -#include <asm/cacheflush.h> -#include <asm/tlbflush.h> -#include <asm/page.h> - -EXPORT_SYMBOL(cpu_dcache_clean_area); -EXPORT_SYMBOL(cpu_set_pte); - -EXPORT_SYMBOL(__cpuc_coherent_kern_range); diff --git a/arch/unicore32/mm/proc-ucv2.S b/arch/unicore32/mm/proc-ucv2.S deleted file mode 100644 index 18f8c4fb21a0..000000000000 --- a/arch/unicore32/mm/proc-ucv2.S +++ /dev/null @@ -1,131 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * linux/arch/unicore32/mm/proc-ucv2.S - * - * Code specific to PKUnity SoC and UniCore ISA - * - * Copyright (C) 2001-2010 GUAN Xue-tao - */ -#include <linux/init.h> -#include <linux/linkage.h> -#include <linux/pgtable.h> -#include <asm/assembler.h> -#include <asm/hwcap.h> -#include <asm/pgtable-hwdef.h> - -#include "proc-macros.S" - -ENTRY(cpu_proc_fin) - stm.w (lr), [sp-] - mov ip, #PSR_R_BIT | PSR_I_BIT | PRIV_MODE - mov.a asr, ip - b.l __cpuc_flush_kern_all - ldm.w (pc), [sp]+ - -/* - * cpu_reset(loc) - * - * Perform a soft reset of the system. Put the CPU into the - * same state as it would be if it had been reset, and branch - * to what would be the reset vector. - * - * - loc - location to jump to for soft reset - */ - .align 5 -ENTRY(cpu_reset) - mov ip, #0 - movc p0.c5, ip, #28 @ Cache invalidate all - nop8 - - movc p0.c6, ip, #6 @ TLB invalidate all - nop8 - - movc ip, p0.c1, #0 @ ctrl register - or ip, ip, #0x2000 @ vector base address - andn ip, ip, #0x000f @ ............idam - movc p0.c1, ip, #0 @ disable caches and mmu - nop - mov pc, r0 @ jump to loc - nop8 - -/* - * cpu_do_idle() - * - * Idle the processor (eg, wait for interrupt). - * - * IRQs are already disabled. - */ -ENTRY(cpu_do_idle) - mov r0, #0 @ PCI address - .rept 8 - ldw r1, [r0] - .endr - mov pc, lr - -ENTRY(cpu_dcache_clean_area) -#ifndef CONFIG_CPU_DCACHE_LINE_DISABLE - csub.a r1, #MAX_AREA_SIZE - bsg 101f - mov r9, #PAGE_SZ - sub r9, r9, #1 @ PAGE_MASK -1: va2pa r0, r10, r11, r12, r13 @ r10 is PA - b 3f -2: cand.a r0, r9 - beq 1b -3: movc p0.c5, r10, #11 @ clean D entry - nop8 - add r0, r0, #CACHE_LINESIZE - add r10, r10, #CACHE_LINESIZE - sub.a r1, r1, #CACHE_LINESIZE - bua 2b - mov pc, lr -#endif -101: mov ip, #0 - movc p0.c5, ip, #10 @ Dcache clean all - nop8 - - mov pc, lr - -/* - * cpu_do_switch_mm(pgd_phys) - * - * Set the translation table base pointer to be pgd_phys - * - * - pgd_phys - physical address of new pgd - * - * It is assumed that: - * - we are not using split page tables - */ - .align 5 -ENTRY(cpu_do_switch_mm) - movc p0.c2, r0, #0 @ update page table ptr - nop8 - - movc p0.c6, ip, #6 @ TLB invalidate all - nop8 - - mov pc, lr - -/* - * cpu_set_pte(ptep, pte) - * - * Set a level 2 translation table entry. - * - * - ptep - pointer to level 2 translation table entry - * - pte - PTE value to store - */ - .align 5 -ENTRY(cpu_set_pte) - stw r1, [r0] -#ifndef CONFIG_CPU_DCACHE_LINE_DISABLE - sub r2, r0, #PAGE_OFFSET - movc p0.c5, r2, #11 @ Dcache clean line - nop8 -#else - mov ip, #0 - movc p0.c5, ip, #10 @ Dcache clean all - nop8 - @dcacheline_flush r0, r2, ip -#endif - mov pc, lr - diff --git a/arch/unicore32/mm/tlb-ucv2.S b/arch/unicore32/mm/tlb-ucv2.S deleted file mode 100644 index 0ce9c6b6f1db..000000000000 --- a/arch/unicore32/mm/tlb-ucv2.S +++ /dev/null @@ -1,86 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * linux/arch/unicore32/mm/tlb-ucv2.S - * - * Code specific to PKUnity SoC and UniCore ISA - * - * Copyright (C) 2001-2010 GUAN Xue-tao - */ -#include <linux/init.h> -#include <linux/linkage.h> -#include <asm/assembler.h> -#include <asm/page.h> -#include <asm/tlbflush.h> -#include "proc-macros.S" - -/* - * __cpu_flush_user_tlb_range(start, end, vma) - * - * Invalidate a range of TLB entries in the specified address space. - * - * - start - start address (may not be aligned) - * - end - end address (exclusive, may not be aligned) - * - vma - vma_struct describing address range - */ -ENTRY(__cpu_flush_user_tlb_range) -#ifndef CONFIG_CPU_TLB_SINGLE_ENTRY_DISABLE - mov r0, r0 >> #PAGE_SHIFT @ align address - mov r0, r0 << #PAGE_SHIFT - vma_vm_flags r2, r2 @ get vma->vm_flags -1: - movc p0.c6, r0, #3 - nop8 - - cand.a r2, #VM_EXEC @ Executable area ? - beq 2f - - movc p0.c6, r0, #5 - nop8 -2: - add r0, r0, #PAGE_SZ - csub.a r0, r1 - beb 1b -#else - movc p0.c6, r0, #2 - nop8 - - cand.a r2, #VM_EXEC @ Executable area ? - beq 2f - - movc p0.c6, r0, #4 - nop8 -2: -#endif - mov pc, lr - -/* - * __cpu_flush_kern_tlb_range(start,end) - * - * Invalidate a range of kernel TLB entries - * - * - start - start address (may not be aligned) - * - end - end address (exclusive, may not be aligned) - */ -ENTRY(__cpu_flush_kern_tlb_range) -#ifndef CONFIG_CPU_TLB_SINGLE_ENTRY_DISABLE - mov r0, r0 >> #PAGE_SHIFT @ align address - mov r0, r0 << #PAGE_SHIFT -1: - movc p0.c6, r0, #3 - nop8 - - movc p0.c6, r0, #5 - nop8 - - add r0, r0, #PAGE_SZ - csub.a r0, r1 - beb 1b -#else - movc p0.c6, r0, #2 - nop8 - - movc p0.c6, r0, #4 - nop8 -#endif - mov pc, lr - |