mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
ARM updates for 7.4-rc1
- remove supersection support - set "current" earlier to avoid KASAN issues - fix a couple of corner cases in the alignment handler - fix wrong free function in iommu allocation path - cacheinfo updates - properly align hugetlb mappings - always set endianness on xscale - fix clang backtracer - avoid replacing active_asids if already 0 -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEuNNh8scc2k/wOAE+9OeQG+StrGQFAmrZ0I8ACgkQ9OeQG+St rGSolA//VJVHLDLnM5UGhlmazwNnJVJPElYCLRNLJroLgaY5XznBJObeiMU9/xvS wFW/PBgqKZiFDtkvqVNp8fFgNCivKhJZhY7oH2a86y61YEO1rHNJb5pA7DQGcxaG pzeMjs4Ot0eLhqsJAUCr1ZxGM5OwbxoHgnABZhE0jlcNFMrJirrKwIQlrcyHFimp 3O/1G73UvHZVFCeXUmEUZYwJCQ9f11WgEM4DFu7SSYQBhoKRkaYI4/MljueqEiZr /jsK14nZFbZCB0Kf9mBM7W10E5KQycIlsuDidB+FmIfIfPIL2UZUdACLEztPA6hP QfCDITJQaAnyf4B6Mk0QzqQij5DKjmU6qk/2FnOM5pYOSlmg2H900gxv62NXzTLz HIOWYwvDv+hA9acHRtSCgAmBF6oT6/HzDCHwZG5T8DmADn1wvvY4PkFg+q2Qh2pc 9WQhVm5xkXsqBVnjhMgPTpjT4lWmPjFeZmeHL+KuQndmfc9kQR26UJNV3TqH/qGy mJVMjKYNxQQs7/kU8pqImOTcDYoKgNPi1XgQKG7kUi2vTUeko3mI/kNCv77tZZMZ U88wiljFRnae9xTa8NxqFmZka+ASxpOoyOLhRV4/VcSvKwY9L5DpNa7sq7MIhy8j XM3cLDz7PeIJOwBJviz4vOZnD9BhK9n7bHqO2e0LcaIPdlietAc= =S0pM -----END PGP SIGNATURE----- Merge tag 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rmk/linux Pull ARM updates from Russell King: - remove supersection support - set "current" earlier to avoid KASAN issues - fix a couple of corner cases in the alignment handler - fix wrong free function in iommu allocation path - cacheinfo updates - properly align hugetlb mappings - always set endianness on xscale - fix clang backtracer - avoid replacing active_asids if already 0 * tag 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rmk/linux: ARM: 9493/1: asid: Do not replace active_asids if already 0 ARM: 9490/1: backtrace-clang: fix wrong sp usage for unwinding ARM: 9482/5: decompressor: always set endianess on xscale ARM: 9524/1: mm: align hugetlb mappings to the huge page size ARM: 9523/1: topology: allocate the cacheinfo early on the boot CPU ARM: 9522/1: cacheinfo: guard the CLIDR read in populate_cache_leaves() ARM: 9521/1: cacheinfo: count external caches in early_cache_level() ARM: 9520/1: cacheinfo: avoid out-of-bounds write in populate_cache_leaves() ARM: 9519/1: dma-mapping: Fix wrong free function in __iommu_alloc_simple() error path ARM: 9492/1: alignment: fix LSR #32 and ASR #32 offset decoding ARM: 9491/1: alignment: restore uaccess state on emulation fault ARM: 9488/1: smp: set current pointer in assembly before jumping into C ARM: 9486/1: set !LPAE MAX_PHYSMEM_BITS to 32 and remove supersection mappings
This commit is contained in:
commit
5b6eaf4aeb
|
|
@ -41,14 +41,6 @@ ifeq ($(CONFIG_PXA_SHARPSL_DETECT_MACH_ID),y)
|
|||
OBJS += head-sharpsl.o
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_CPU_ENDIAN_BE32),y)
|
||||
ifeq ($(CONFIG_CPU_CP15),y)
|
||||
OBJS += big-endian.o
|
||||
else
|
||||
# The endian should be set by h/w design.
|
||||
endif
|
||||
endif
|
||||
|
||||
#
|
||||
# We now have a PIC decompressor implementation. Decompressors running
|
||||
# from RAM should not define ZTEXTADDR. Decompressors running directly
|
||||
|
|
|
|||
|
|
@ -1,14 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* linux/arch/arm/boot/compressed/big-endian.S
|
||||
*
|
||||
* Switch CPU into big endian mode.
|
||||
* Author: Nicolas Pitre
|
||||
*/
|
||||
|
||||
.section ".start", "ax"
|
||||
|
||||
mrc p15, 0, r0, c1, c0, 0 @ read control reg
|
||||
orr r0, r0, #(1 << 7) @ enable big endian mode
|
||||
mcr p15, 0, r0, c1, c0, 0 @ write control reg
|
||||
|
||||
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/cp15.h>
|
||||
|
||||
.section ".start", "ax"
|
||||
|
||||
|
|
@ -14,6 +15,23 @@ __XScale_start:
|
|||
|
||||
@ Preserve r8/r7 i.e. kernel entry values
|
||||
|
||||
@ set correct endianness for ixp4xx regardless of bootloader
|
||||
mrc p15, 0, r0, c1, c0, 0
|
||||
#ifdef CONFIG_CPU_BIG_ENDIAN
|
||||
orr r0, r0, #CR_B @ enable big endian mode
|
||||
#else
|
||||
bic r0, r0, #CR_B
|
||||
#endif
|
||||
mcr p15, 0, r0, c1, c0, 0
|
||||
0: mrc p15, 0, r0, c1, c0, 0
|
||||
tst r0, #0x80
|
||||
#ifdef CONFIG_CPU_BIG_ENDIAN
|
||||
beq 0b
|
||||
#else
|
||||
bne 0b
|
||||
#endif
|
||||
sub pc, pc, #4 @ flush instruction pipeline
|
||||
|
||||
@ Data cache might be active.
|
||||
@ Be sure to flush kernel binary out of the cache,
|
||||
@ whatever state it is, before it is turned off.
|
||||
|
|
|
|||
|
|
@ -18,27 +18,10 @@
|
|||
* DOMAIN_IO - domain 2 includes all IO only
|
||||
* DOMAIN_USER - domain 1 includes all user memory only
|
||||
* DOMAIN_KERNEL - domain 0 includes all kernel memory only
|
||||
*
|
||||
* The domain numbering depends on whether we support 36 physical
|
||||
* address for I/O or not. Addresses above the 32 bit boundary can
|
||||
* only be mapped using supersections and supersections can only
|
||||
* be set for domain 0. We could just default to DOMAIN_IO as zero,
|
||||
* but there may be systems with supersection support and no 36-bit
|
||||
* addressing. In such cases, we want to map system memory with
|
||||
* supersections to reduce TLB misses and footprint.
|
||||
*
|
||||
* 36-bit addressing and supersections are only available on
|
||||
* CPUs based on ARMv6+ or the Intel XSC3 core.
|
||||
*/
|
||||
#ifndef CONFIG_IO_36
|
||||
#define DOMAIN_KERNEL 0
|
||||
#define DOMAIN_USER 1
|
||||
#define DOMAIN_IO 2
|
||||
#else
|
||||
#define DOMAIN_KERNEL 2
|
||||
#define DOMAIN_USER 1
|
||||
#define DOMAIN_IO 0
|
||||
#endif
|
||||
#define DOMAIN_VECTORS 3
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -89,9 +89,9 @@
|
|||
|
||||
#if !defined(CONFIG_SMP) && !defined(CONFIG_ARM_LPAE)
|
||||
/*
|
||||
* Allow 16MB-aligned ioremap pages
|
||||
* Allow 2MB-aligned ioremap pages
|
||||
*/
|
||||
#define IOREMAP_MAX_ORDER 24
|
||||
#define IOREMAP_MAX_ORDER 21
|
||||
#endif
|
||||
|
||||
#define VECTORS_BASE UL(0xffff0000)
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@
|
|||
#define PMD_SECT_APX (_AT(pmdval_t, 1) << 15) /* v6 */
|
||||
#define PMD_SECT_S (_AT(pmdval_t, 1) << 16) /* v6 */
|
||||
#define PMD_SECT_nG (_AT(pmdval_t, 1) << 17) /* v6 */
|
||||
#define PMD_SECT_SUPER (_AT(pmdval_t, 1) << 18) /* v6 */
|
||||
#define PMD_SECT_AF (_AT(pmdval_t, 0))
|
||||
|
||||
#define PMD_SECT_UNCACHED (_AT(pmdval_t, 0))
|
||||
|
|
|
|||
|
|
@ -96,13 +96,6 @@
|
|||
#define SECTION_SIZE (1UL << SECTION_SHIFT)
|
||||
#define SECTION_MASK (~(SECTION_SIZE-1))
|
||||
|
||||
/*
|
||||
* ARMv6 supersection address mask and size definitions.
|
||||
*/
|
||||
#define SUPERSECTION_SHIFT 24
|
||||
#define SUPERSECTION_SIZE (1UL << SUPERSECTION_SHIFT)
|
||||
#define SUPERSECTION_MASK (~(SUPERSECTION_SIZE-1))
|
||||
|
||||
#define USER_PTRS_PER_PGD (TASK_SIZE / PGDIR_SIZE)
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ extern void set_smp_ipi_range(int ipi_base, int nr_ipi);
|
|||
* Called from platform specific assembly code, this is the
|
||||
* secondary CPU entry point.
|
||||
*/
|
||||
asmlinkage void secondary_start_kernel(struct task_struct *task);
|
||||
asmlinkage void secondary_start_kernel(void);
|
||||
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -19,7 +19,11 @@
|
|||
* These can be overridden in your mach/memory.h.
|
||||
*/
|
||||
#if !defined(MAX_PHYSMEM_BITS) || !defined(SECTION_SIZE_BITS)
|
||||
#ifdef CONFIG_ARM_LPAE
|
||||
#define MAX_PHYSMEM_BITS 36
|
||||
#else
|
||||
#define MAX_PHYSMEM_BITS 32
|
||||
#endif
|
||||
#define SECTION_SIZE_BITS 28
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -80,19 +80,21 @@ static void ci_leaf_init(struct cacheinfo *this_leaf,
|
|||
this_leaf->type = type;
|
||||
}
|
||||
|
||||
static bool clidr_present(void)
|
||||
{
|
||||
/* CLIDR is not present before ARMv7/v7m */
|
||||
if (cpu_architecture() < CPU_ARCH_ARMv7)
|
||||
return false;
|
||||
|
||||
/* Don't try reading CLIDR if CTR declares old format */
|
||||
return FIELD_GET(CTR_FORMAT_MASK, read_cpuid_cachetype()) == CTR_FORMAT_ARMV7;
|
||||
}
|
||||
|
||||
static int detect_cache_level(unsigned int *level_p, unsigned int *leaves_p)
|
||||
{
|
||||
unsigned int ctype, level, leaves;
|
||||
u32 ctr, format;
|
||||
|
||||
/* CLIDR is not present before ARMv7/v7m */
|
||||
if (cpu_architecture() < CPU_ARCH_ARMv7)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* Don't try reading CLIDR if CTR declares old format */
|
||||
ctr = read_cpuid_cachetype();
|
||||
format = FIELD_GET(CTR_FORMAT_MASK, ctr);
|
||||
if (format != CTR_FORMAT_ARMV7)
|
||||
if (!clidr_present())
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
for (level = 1, leaves = 0; level <= MAX_CACHE_LEVEL; level++) {
|
||||
|
|
@ -111,13 +113,6 @@ static int detect_cache_level(unsigned int *level_p, unsigned int *leaves_p)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int early_cache_level(unsigned int cpu)
|
||||
{
|
||||
struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
|
||||
|
||||
return detect_cache_level(&this_cpu_ci->num_levels, &this_cpu_ci->num_leaves);
|
||||
}
|
||||
|
||||
int init_cache_level(unsigned int cpu)
|
||||
{
|
||||
unsigned int level, leaves;
|
||||
|
|
@ -146,26 +141,32 @@ int init_cache_level(unsigned int cpu)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int early_cache_level(unsigned int cpu)
|
||||
{
|
||||
return init_cache_level(cpu);
|
||||
}
|
||||
|
||||
int populate_cache_leaves(unsigned int cpu)
|
||||
{
|
||||
unsigned int level, idx;
|
||||
enum cache_type type;
|
||||
struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
|
||||
struct cacheinfo *this_leaf = this_cpu_ci->info_list;
|
||||
unsigned int arch = cpu_architecture();
|
||||
struct cacheinfo *infos = this_cpu_ci->info_list;
|
||||
|
||||
/* CLIDR is not present before ARMv7/v7m */
|
||||
if (arch < CPU_ARCH_ARMv7)
|
||||
return -EOPNOTSUPP;
|
||||
/* The device tree can describe caches CLIDR cannot fill in. */
|
||||
if (!clidr_present())
|
||||
return -ENOENT;
|
||||
|
||||
for (idx = 0, level = 1; level <= this_cpu_ci->num_levels &&
|
||||
idx < this_cpu_ci->num_leaves; idx++, level++) {
|
||||
idx < this_cpu_ci->num_leaves; level++) {
|
||||
type = get_cache_type(level);
|
||||
if (type == CACHE_TYPE_SEPARATE) {
|
||||
ci_leaf_init(this_leaf++, CACHE_TYPE_DATA, level);
|
||||
ci_leaf_init(this_leaf++, CACHE_TYPE_INST, level);
|
||||
if (idx + 1 >= this_cpu_ci->num_leaves)
|
||||
break;
|
||||
ci_leaf_init(&infos[idx++], CACHE_TYPE_DATA, level);
|
||||
ci_leaf_init(&infos[idx++], CACHE_TYPE_INST, level);
|
||||
} else {
|
||||
ci_leaf_init(this_leaf++, type, level);
|
||||
ci_leaf_init(&infos[idx++], type, level);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include <linux/efi.h>
|
||||
#include <linux/memblock.h>
|
||||
#include <linux/screen_info.h>
|
||||
#include <linux/sizes.h>
|
||||
|
||||
#include <asm/efi.h>
|
||||
#include <asm/mach/map.h>
|
||||
|
|
@ -54,6 +55,18 @@ int __init efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md)
|
|||
.length = md->num_pages * EFI_PAGE_SIZE,
|
||||
};
|
||||
|
||||
/*
|
||||
* Non-LPAE page tables cannot map EFI runtime regions extending
|
||||
* beyond the 32-bit physical address space.
|
||||
*/
|
||||
if (!IS_ENABLED(CONFIG_ARM_LPAE) &&
|
||||
(md->phys_addr >= SZ_4G ||
|
||||
md->num_pages > (SZ_4G - md->phys_addr) / EFI_PAGE_SIZE)) {
|
||||
pr_warn("EFI runtime region at 0x%llx exceeds 32-bit physical address space\n",
|
||||
md->phys_addr);
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Order is important here: memory regions may have all of the
|
||||
* bits below set (and usually do), so we check them in order of
|
||||
|
|
|
|||
|
|
@ -116,6 +116,7 @@ ENTRY(secondary_startup)
|
|||
ldr r7, __secondary_data @ reload r7
|
||||
ldr sp, [r7, #12] @ set up the stack pointer
|
||||
ldr r0, [r7, #16] @ set up task pointer
|
||||
set_current r0, r1
|
||||
mov fp, #0
|
||||
b secondary_start_kernel
|
||||
ENDPROC(secondary_startup)
|
||||
|
|
|
|||
|
|
@ -442,6 +442,7 @@ ENTRY(__secondary_switched)
|
|||
adr_l r7, secondary_data + 12 @ get secondary_data.stack
|
||||
ldr sp, [r7]
|
||||
ldr r0, [r7, #4] @ get secondary_data.task
|
||||
set_current r0, r1
|
||||
mov fp, #0
|
||||
b secondary_start_kernel
|
||||
ENDPROC(__secondary_switched)
|
||||
|
|
|
|||
|
|
@ -371,12 +371,9 @@ void __noreturn arch_cpu_idle_dead(void)
|
|||
*/
|
||||
__asm__("mov sp, %0\n"
|
||||
" mov fp, #0\n"
|
||||
" mov r0, %1\n"
|
||||
" b secondary_start_kernel"
|
||||
:
|
||||
: "r" (task_stack_page(current) + THREAD_SIZE - 8),
|
||||
"r" (current)
|
||||
: "r0");
|
||||
: "r" (task_stack_page(current) + THREAD_SIZE - 8));
|
||||
|
||||
unreachable();
|
||||
}
|
||||
|
|
@ -397,23 +394,15 @@ static void smp_store_cpu_info(unsigned int cpuid)
|
|||
check_cpu_icache_size(cpuid);
|
||||
}
|
||||
|
||||
static void set_current(struct task_struct *cur)
|
||||
{
|
||||
/* Set TPIDRURO */
|
||||
asm("mcr p15, 0, %0, c13, c0, 3" :: "r"(cur) : "memory");
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the secondary CPU boot entry. We're using this CPUs
|
||||
* idle thread stack, but a set of temporary page tables.
|
||||
*/
|
||||
asmlinkage void secondary_start_kernel(struct task_struct *task)
|
||||
asmlinkage void secondary_start_kernel(void)
|
||||
{
|
||||
struct mm_struct *mm = &init_mm;
|
||||
unsigned int cpu;
|
||||
|
||||
set_current(task);
|
||||
|
||||
secondary_biglittle_init();
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/arch_topology.h>
|
||||
#include <linux/cacheinfo.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/cpufreq.h>
|
||||
#include <linux/cpumask.h>
|
||||
|
|
@ -238,8 +239,20 @@ void store_cpu_topology(unsigned int cpuid)
|
|||
*/
|
||||
void __init init_cpu_topology(void)
|
||||
{
|
||||
int cpu, ret;
|
||||
|
||||
reset_cpu_topology();
|
||||
smp_wmb();
|
||||
|
||||
parse_dt_topology();
|
||||
|
||||
for_each_possible_cpu(cpu) {
|
||||
ret = fetch_cache_info(cpu);
|
||||
if (!ret)
|
||||
continue;
|
||||
/* CPUs without a usable CLIDR return -EOPNOTSUPP. */
|
||||
if (ret != -ENOENT && ret != -EOPNOTSUPP)
|
||||
pr_err("Early cacheinfo failed, ret = %d\n", ret);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -107,8 +107,10 @@ ENDPROC(c_backtrace)
|
|||
|
||||
/*
|
||||
* Switches the current frame to be the frame for dump_stack.
|
||||
* (Only in case of current task using current registers)
|
||||
*/
|
||||
add frame, sp, #24 @ switch to false frame
|
||||
cmp frame, fp
|
||||
addeq frame, sp, #24 @ switch to false frame
|
||||
for_each_frame: tst frame, mask @ Check for address exceptions
|
||||
bne no_frame
|
||||
|
||||
|
|
|
|||
|
|
@ -328,7 +328,6 @@ config CPU_XSC3
|
|||
select CPU_PABRT_LEGACY
|
||||
select CPU_THUMB_CAPABLE
|
||||
select CPU_TLB_V4WBI if MMU
|
||||
select IO_36
|
||||
|
||||
# Marvell PJ1 (Mohawk)
|
||||
config CPU_MOHAWK
|
||||
|
|
@ -676,12 +675,6 @@ config CPU_V7M_NUM_IRQ
|
|||
|
||||
If unsure, keep default value.
|
||||
|
||||
#
|
||||
# CPU supports 36-bit I/O
|
||||
#
|
||||
config IO_36
|
||||
bool
|
||||
|
||||
comment "Processor Features"
|
||||
|
||||
config ARM_LPAE
|
||||
|
|
|
|||
|
|
@ -341,6 +341,8 @@ static int
|
|||
do_alignment_ldrhstrh(unsigned long addr, u32 instr, struct pt_regs *regs)
|
||||
{
|
||||
unsigned int rd = RD_BITS(instr);
|
||||
unsigned int ua_flags;
|
||||
bool ua_saved = false;
|
||||
|
||||
ai_half += 1;
|
||||
|
||||
|
|
@ -364,10 +366,11 @@ do_alignment_ldrhstrh(unsigned long addr, u32 instr, struct pt_regs *regs)
|
|||
user:
|
||||
if (LDST_L_BIT(instr)) {
|
||||
unsigned long val;
|
||||
unsigned int __ua_flags = uaccess_save_and_enable();
|
||||
|
||||
ua_flags = uaccess_save_and_enable();
|
||||
ua_saved = true;
|
||||
get16t_unaligned_check(val, addr);
|
||||
uaccess_restore(__ua_flags);
|
||||
uaccess_restore(ua_flags);
|
||||
|
||||
/* signed half-word? */
|
||||
if (instr & 0x40)
|
||||
|
|
@ -375,14 +378,17 @@ do_alignment_ldrhstrh(unsigned long addr, u32 instr, struct pt_regs *regs)
|
|||
|
||||
regs->uregs[rd] = val;
|
||||
} else {
|
||||
unsigned int __ua_flags = uaccess_save_and_enable();
|
||||
ua_flags = uaccess_save_and_enable();
|
||||
ua_saved = true;
|
||||
put16t_unaligned_check(regs->uregs[rd], addr);
|
||||
uaccess_restore(__ua_flags);
|
||||
uaccess_restore(ua_flags);
|
||||
}
|
||||
|
||||
return TYPE_LDST;
|
||||
|
||||
fault:
|
||||
if (ua_saved)
|
||||
uaccess_restore(ua_flags);
|
||||
return TYPE_FAULT;
|
||||
}
|
||||
|
||||
|
|
@ -391,6 +397,8 @@ do_alignment_ldrdstrd(unsigned long addr, u32 instr, struct pt_regs *regs)
|
|||
{
|
||||
unsigned int rd = RD_BITS(instr);
|
||||
unsigned int rd2;
|
||||
unsigned int ua_flags;
|
||||
bool ua_saved = false;
|
||||
int load;
|
||||
|
||||
if ((instr & 0xfe000000) == 0xe8000000) {
|
||||
|
|
@ -425,26 +433,30 @@ do_alignment_ldrdstrd(unsigned long addr, u32 instr, struct pt_regs *regs)
|
|||
user:
|
||||
if (load) {
|
||||
unsigned long val, val2;
|
||||
unsigned int __ua_flags = uaccess_save_and_enable();
|
||||
|
||||
ua_flags = uaccess_save_and_enable();
|
||||
ua_saved = true;
|
||||
get32t_unaligned_check(val, addr);
|
||||
get32t_unaligned_check(val2, addr + 4);
|
||||
|
||||
uaccess_restore(__ua_flags);
|
||||
uaccess_restore(ua_flags);
|
||||
|
||||
regs->uregs[rd] = val;
|
||||
regs->uregs[rd2] = val2;
|
||||
} else {
|
||||
unsigned int __ua_flags = uaccess_save_and_enable();
|
||||
ua_flags = uaccess_save_and_enable();
|
||||
ua_saved = true;
|
||||
put32t_unaligned_check(regs->uregs[rd], addr);
|
||||
put32t_unaligned_check(regs->uregs[rd2], addr + 4);
|
||||
uaccess_restore(__ua_flags);
|
||||
uaccess_restore(ua_flags);
|
||||
}
|
||||
|
||||
return TYPE_LDST;
|
||||
bad:
|
||||
return TYPE_ERROR;
|
||||
fault:
|
||||
if (ua_saved)
|
||||
uaccess_restore(ua_flags);
|
||||
return TYPE_FAULT;
|
||||
}
|
||||
|
||||
|
|
@ -452,6 +464,8 @@ static int
|
|||
do_alignment_ldrstr(unsigned long addr, u32 instr, struct pt_regs *regs)
|
||||
{
|
||||
unsigned int rd = RD_BITS(instr);
|
||||
unsigned int ua_flags;
|
||||
bool ua_saved = false;
|
||||
|
||||
ai_word += 1;
|
||||
|
||||
|
|
@ -469,18 +483,22 @@ do_alignment_ldrstr(unsigned long addr, u32 instr, struct pt_regs *regs)
|
|||
trans:
|
||||
if (LDST_L_BIT(instr)) {
|
||||
unsigned int val;
|
||||
unsigned int __ua_flags = uaccess_save_and_enable();
|
||||
ua_flags = uaccess_save_and_enable();
|
||||
ua_saved = true;
|
||||
get32t_unaligned_check(val, addr);
|
||||
uaccess_restore(__ua_flags);
|
||||
uaccess_restore(ua_flags);
|
||||
regs->uregs[rd] = val;
|
||||
} else {
|
||||
unsigned int __ua_flags = uaccess_save_and_enable();
|
||||
ua_flags = uaccess_save_and_enable();
|
||||
ua_saved = true;
|
||||
put32t_unaligned_check(regs->uregs[rd], addr);
|
||||
uaccess_restore(__ua_flags);
|
||||
uaccess_restore(ua_flags);
|
||||
}
|
||||
return TYPE_LDST;
|
||||
|
||||
fault:
|
||||
if (ua_saved)
|
||||
uaccess_restore(ua_flags);
|
||||
return TYPE_FAULT;
|
||||
}
|
||||
|
||||
|
|
@ -502,6 +520,8 @@ do_alignment_ldmstm(unsigned long addr, u32 instr, struct pt_regs *regs)
|
|||
{
|
||||
unsigned int rd, rn, correction, nr_regs, regbits;
|
||||
unsigned long eaddr, newaddr;
|
||||
unsigned int ua_flags;
|
||||
bool ua_saved = false;
|
||||
|
||||
if (LDM_S_BIT(instr))
|
||||
goto bad;
|
||||
|
|
@ -547,7 +567,8 @@ do_alignment_ldmstm(unsigned long addr, u32 instr, struct pt_regs *regs)
|
|||
#endif
|
||||
|
||||
if (user_mode(regs)) {
|
||||
unsigned int __ua_flags = uaccess_save_and_enable();
|
||||
ua_flags = uaccess_save_and_enable();
|
||||
ua_saved = true;
|
||||
for (regbits = REGMASK_BITS(instr), rd = 0; regbits;
|
||||
regbits >>= 1, rd += 1)
|
||||
if (regbits & 1) {
|
||||
|
|
@ -559,7 +580,7 @@ do_alignment_ldmstm(unsigned long addr, u32 instr, struct pt_regs *regs)
|
|||
put32t_unaligned_check(regs->uregs[rd], eaddr);
|
||||
eaddr += 4;
|
||||
}
|
||||
uaccess_restore(__ua_flags);
|
||||
uaccess_restore(ua_flags);
|
||||
} else {
|
||||
for (regbits = REGMASK_BITS(instr), rd = 0; regbits;
|
||||
regbits >>= 1, rd += 1)
|
||||
|
|
@ -581,6 +602,8 @@ do_alignment_ldmstm(unsigned long addr, u32 instr, struct pt_regs *regs)
|
|||
return TYPE_DONE;
|
||||
|
||||
fault:
|
||||
if (ua_saved)
|
||||
uaccess_restore(ua_flags);
|
||||
regs->ARM_pc -= correction;
|
||||
return TYPE_FAULT;
|
||||
|
||||
|
|
@ -892,11 +915,17 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
|
|||
break;
|
||||
|
||||
case SHIFT_LSR:
|
||||
offset.un >>= shiftval;
|
||||
if (shiftval == 0)
|
||||
offset.un = 0;
|
||||
else
|
||||
offset.un >>= shiftval;
|
||||
break;
|
||||
|
||||
case SHIFT_ASR:
|
||||
offset.sn >>= shiftval;
|
||||
if (shiftval == 0)
|
||||
offset.sn >>= 31;
|
||||
else
|
||||
offset.sn >>= shiftval;
|
||||
break;
|
||||
|
||||
case SHIFT_RORRRX:
|
||||
|
|
|
|||
|
|
@ -238,7 +238,7 @@ void check_and_switch_context(struct mm_struct *mm, struct task_struct *tsk)
|
|||
{
|
||||
unsigned long flags;
|
||||
unsigned int cpu = smp_processor_id();
|
||||
u64 asid;
|
||||
u64 asid, old_active_asid;
|
||||
|
||||
check_vmalloc_seq(mm);
|
||||
|
||||
|
|
@ -250,8 +250,17 @@ void check_and_switch_context(struct mm_struct *mm, struct task_struct *tsk)
|
|||
cpu_set_reserved_ttbr0();
|
||||
|
||||
asid = atomic64_read(&mm->context.id);
|
||||
if (!((asid ^ atomic64_read(&asid_generation)) >> ASID_BITS)
|
||||
&& atomic64_xchg(&per_cpu(active_asids, cpu), asid))
|
||||
|
||||
/*
|
||||
* If our active_asids is zero, we are racing with an ASID roll-over
|
||||
* on a different CPU, so skip the update (using cmpxchg if non-zero)
|
||||
* and take the slow path.
|
||||
*/
|
||||
old_active_asid = atomic64_read(&per_cpu(active_asids, cpu));
|
||||
if (old_active_asid &&
|
||||
!((asid ^ atomic64_read(&asid_generation)) >> ASID_BITS) &&
|
||||
atomic64_cmpxchg(&per_cpu(active_asids, cpu),
|
||||
old_active_asid, asid))
|
||||
goto switch_mm_fastpath;
|
||||
|
||||
raw_spin_lock_irqsave(&cpu_asid_lock, flags);
|
||||
|
|
|
|||
|
|
@ -1056,7 +1056,10 @@ static void *__iommu_alloc_simple(struct device *dev, size_t size, gfp_t gfp,
|
|||
return addr;
|
||||
|
||||
err_mapping:
|
||||
__free_from_pool(addr, size);
|
||||
if (coherent_flag == COHERENT)
|
||||
__dma_free_buffer(virt_to_page(addr), size);
|
||||
else
|
||||
__free_from_pool(addr, size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,8 +30,6 @@
|
|||
#include <linux/sizes.h>
|
||||
#include <linux/memblock.h>
|
||||
|
||||
#include <asm/cp15.h>
|
||||
#include <asm/cputype.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/early_ioremap.h>
|
||||
#include <asm/mmu_context.h>
|
||||
|
|
@ -236,39 +234,6 @@ remap_area_sections(unsigned long virt, unsigned long pfn,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
remap_area_supersections(unsigned long virt, unsigned long pfn,
|
||||
size_t size, const struct mem_type *type)
|
||||
{
|
||||
unsigned long addr = virt, end = virt + size;
|
||||
pmd_t *pmd = pmd_off_k(addr);
|
||||
|
||||
/*
|
||||
* Remove and free any PTE-based mapping, and
|
||||
* sync the current kernel mapping.
|
||||
*/
|
||||
unmap_area_sections(virt, size);
|
||||
do {
|
||||
unsigned long super_pmd_val, i;
|
||||
|
||||
super_pmd_val = __pfn_to_phys(pfn) | type->prot_sect |
|
||||
PMD_SECT_SUPER;
|
||||
super_pmd_val |= ((pfn >> (32 - PAGE_SHIFT)) & 0xf) << 20;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
pmd[0] = __pmd(super_pmd_val);
|
||||
pmd[1] = __pmd(super_pmd_val);
|
||||
flush_pmd_entry(pmd);
|
||||
|
||||
addr += PMD_SIZE;
|
||||
pmd += 2;
|
||||
}
|
||||
|
||||
pfn += SUPERSECTION_SIZE >> PAGE_SHIFT;
|
||||
} while (addr < end);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void __iomem * __arm_ioremap_pfn_caller(unsigned long pfn,
|
||||
|
|
@ -278,15 +243,17 @@ static void __iomem * __arm_ioremap_pfn_caller(unsigned long pfn,
|
|||
int err;
|
||||
unsigned long addr;
|
||||
struct vm_struct *area;
|
||||
phys_addr_t paddr = __pfn_to_phys(pfn);
|
||||
phys_addr_t paddr;
|
||||
|
||||
#ifndef CONFIG_ARM_LPAE
|
||||
/*
|
||||
* High mappings must be supersection aligned
|
||||
* The physical range must not extend beyond the 32-bit
|
||||
* phys_addr_t
|
||||
*/
|
||||
if (pfn >= 0x100000 && (paddr & ~SUPERSECTION_MASK))
|
||||
if (((u64)pfn << PAGE_SHIFT) + offset + size > SZ_4G)
|
||||
return NULL;
|
||||
#endif
|
||||
paddr = __pfn_to_phys(pfn);
|
||||
|
||||
type = get_mem_type(mtype);
|
||||
if (!type)
|
||||
|
|
@ -300,7 +267,7 @@ static void __iomem * __arm_ioremap_pfn_caller(unsigned long pfn,
|
|||
/*
|
||||
* Try to reuse one of the static mapping whenever possible.
|
||||
*/
|
||||
if (size && !(sizeof(phys_addr_t) == 4 && pfn >= 0x100000)) {
|
||||
if (size) {
|
||||
struct static_vm *svm;
|
||||
|
||||
svm = find_static_vm_paddr(paddr, size, mtype);
|
||||
|
|
@ -326,13 +293,7 @@ static void __iomem * __arm_ioremap_pfn_caller(unsigned long pfn,
|
|||
area->phys_addr = paddr;
|
||||
|
||||
#if !defined(CONFIG_SMP) && !defined(CONFIG_ARM_LPAE)
|
||||
if (DOMAIN_IO == 0 &&
|
||||
(((cpu_architecture() >= CPU_ARCH_ARMv6) && (get_cr() & CR_XP)) ||
|
||||
cpu_is_xsc3()) && pfn >= 0x100000 &&
|
||||
!((paddr | size | addr) & ~SUPERSECTION_MASK)) {
|
||||
area->flags |= VM_ARM_SECTION_MAPPING;
|
||||
err = remap_area_supersections(addr, pfn, size, type);
|
||||
} else if (!((paddr | size | addr) & ~PMD_MASK)) {
|
||||
if (!((paddr | size | addr) & ~PMD_MASK)) {
|
||||
area->flags |= VM_ARM_SECTION_MAPPING;
|
||||
err = remap_area_sections(addr, pfn, size, type);
|
||||
} else
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include <linux/io.h>
|
||||
#include <linux/personality.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/hugetlb.h>
|
||||
#include <asm/cachetype.h>
|
||||
|
||||
#define COLOUR_ALIGN(addr,pgoff) \
|
||||
|
|
@ -72,7 +73,10 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr,
|
|||
info.length = len;
|
||||
info.low_limit = mm->mmap_base;
|
||||
info.high_limit = TASK_SIZE;
|
||||
info.align_mask = do_align ? (PAGE_MASK & (SHMLBA - 1)) : 0;
|
||||
if (filp && is_file_hugepages(filp))
|
||||
info.align_mask = huge_page_mask_align(filp);
|
||||
else
|
||||
info.align_mask = do_align ? (PAGE_MASK & (SHMLBA - 1)) : 0;
|
||||
info.align_offset = pgoff << PAGE_SHIFT;
|
||||
return vm_unmapped_area(&info);
|
||||
}
|
||||
|
|
@ -123,7 +127,10 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
|
|||
info.length = len;
|
||||
info.low_limit = FIRST_USER_ADDRESS;
|
||||
info.high_limit = mm->mmap_base;
|
||||
info.align_mask = do_align ? (PAGE_MASK & (SHMLBA - 1)) : 0;
|
||||
if (filp && is_file_hugepages(filp))
|
||||
info.align_mask = huge_page_mask_align(filp);
|
||||
else
|
||||
info.align_mask = do_align ? (PAGE_MASK & (SHMLBA - 1)) : 0;
|
||||
info.align_offset = pgoff << PAGE_SHIFT;
|
||||
addr = vm_unmapped_area(&info);
|
||||
|
||||
|
|
|
|||
|
|
@ -854,69 +854,6 @@ static void __init alloc_init_p4d(pgd_t *pgd, unsigned long addr,
|
|||
} while (p4d++, addr = next, addr != end);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_ARM_LPAE
|
||||
static void __init create_36bit_mapping(struct mm_struct *mm,
|
||||
struct map_desc *md,
|
||||
const struct mem_type *type,
|
||||
bool ng)
|
||||
{
|
||||
unsigned long addr, length, end;
|
||||
phys_addr_t phys;
|
||||
pgd_t *pgd;
|
||||
|
||||
addr = md->virtual;
|
||||
phys = __pfn_to_phys(md->pfn);
|
||||
length = PAGE_ALIGN(md->length);
|
||||
|
||||
if (!(cpu_architecture() >= CPU_ARCH_ARMv6 || cpu_is_xsc3())) {
|
||||
pr_err("MM: CPU does not support supersection mapping for 0x%08llx at 0x%08lx\n",
|
||||
(long long)__pfn_to_phys((u64)md->pfn), addr);
|
||||
return;
|
||||
}
|
||||
|
||||
/* N.B. ARMv6 supersections are only defined to work with domain 0.
|
||||
* Since domain assignments can in fact be arbitrary, the
|
||||
* 'domain == 0' check below is required to insure that ARMv6
|
||||
* supersections are only allocated for domain 0 regardless
|
||||
* of the actual domain assignments in use.
|
||||
*/
|
||||
if (type->domain) {
|
||||
pr_err("MM: invalid domain in supersection mapping for 0x%08llx at 0x%08lx\n",
|
||||
(long long)__pfn_to_phys((u64)md->pfn), addr);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((addr | length | __pfn_to_phys(md->pfn)) & ~SUPERSECTION_MASK) {
|
||||
pr_err("MM: cannot create mapping for 0x%08llx at 0x%08lx invalid alignment\n",
|
||||
(long long)__pfn_to_phys((u64)md->pfn), addr);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Shift bits [35:32] of address into bits [23:20] of PMD
|
||||
* (See ARMv6 spec).
|
||||
*/
|
||||
phys |= (((md->pfn >> (32 - PAGE_SHIFT)) & 0xF) << 20);
|
||||
|
||||
pgd = pgd_offset(mm, addr);
|
||||
end = addr + length;
|
||||
do {
|
||||
p4d_t *p4d = p4d_offset(pgd, addr);
|
||||
pud_t *pud = pud_offset(p4d, addr);
|
||||
pmd_t *pmd = pmd_offset(pud, addr);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
*pmd++ = __pmd(phys | type->prot_sect | PMD_SECT_SUPER |
|
||||
(ng ? PMD_SECT_nG : 0));
|
||||
|
||||
addr += SUPERSECTION_SIZE;
|
||||
phys += SUPERSECTION_SIZE;
|
||||
pgd += SUPERSECTION_SIZE >> PGDIR_SHIFT;
|
||||
} while (addr != end);
|
||||
}
|
||||
#endif /* !CONFIG_ARM_LPAE */
|
||||
|
||||
static void __init __create_mapping(struct mm_struct *mm, struct map_desc *md,
|
||||
void *(*alloc)(unsigned long sz),
|
||||
bool ng)
|
||||
|
|
@ -928,16 +865,6 @@ static void __init __create_mapping(struct mm_struct *mm, struct map_desc *md,
|
|||
|
||||
type = &mem_types[md->type];
|
||||
|
||||
#ifndef CONFIG_ARM_LPAE
|
||||
/*
|
||||
* Catch 36-bit addresses
|
||||
*/
|
||||
if (md->pfn >= 0x100000) {
|
||||
create_36bit_mapping(mm, md, type, ng);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
addr = md->virtual & PAGE_MASK;
|
||||
phys = __pfn_to_phys(md->pfn);
|
||||
length = PAGE_ALIGN(md->length + (md->virtual & ~PAGE_MASK));
|
||||
|
|
@ -964,8 +891,7 @@ static void __init __create_mapping(struct mm_struct *mm, struct map_desc *md,
|
|||
* 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 and
|
||||
* supersections.
|
||||
* offsets, and we take full advantage of sections.
|
||||
*/
|
||||
static void __init create_mapping(struct map_desc *md)
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user