Merge branch 'for-linus' of git://git.armlinux.org.uk/~rmk/linux-arm
Pull ARM updates from Russell King: "Included in this update are: - Patches from Gregory Clement to fix the coherent DMA cases in our dma-mapping code. - A number of CPU errata updates and fixes. - ARM cpuidle improvements from Jisheng Zhang. - Fix from Kees for the location of _etext. - Cleanups from Masahiro Yamada to avoid duplicated messages during the kernel build, and remove CONFIG_ARCH_HAS_BARRIERS. - Remove a udelay loop limitation, allowing for faster CPUs to calibrate the delay correctly. - Cleanup some left-overs from the SW PAN implementation. - Ensure that a modified address limit is not visible to exception handlers" * 'for-linus' of git://git.armlinux.org.uk/~rmk/linux-arm: (21 commits) ARM: 8586/1: cpuidle: make arm_cpuidle_suspend() a bit more efficient ARM: 8585/1: cpuidle: fix !cpuidle_ops[cpu].init case during init ARM: 8561/4: dma-mapping: Fix the coherent case when iommu is used ARM: 8561/3: dma-mapping: Don't use outer_flush_range when the L2C is coherent ARM: 8560/1: errata: Workaround errata A12 825619 / A17 852421 ARM: 8559/1: errata: Workaround erratum A12 821420 ARM: 8558/1: errata: Workaround errata A12 818325/852422 A17 852423 ARM: save and reset the address limit when entering an exception ARM: 8577/1: Fix Cortex-A15 798181 errata initialization ARM: 8584/1: floppy: avoid gcc-6 warning ARM: 8583/1: mm: fix location of _etext ARM: 8582/1: remove unused CONFIG_ARCH_HAS_BARRIERS ARM: 8306/1: loop_udelay: remove bogomips value limitation ARM: 8581/1: add missing <asm/prom.h> to arch/arm/kernel/devtree.c ARM: 8576/1: avoid duplicating "Kernel: arch/arm/boot/*Image is ready" ARM: 8556/1: on a generic DT system: do not touch l2x0 ARM: uaccess: remove put_user() code duplication ARM: 8580/1: Remove orphaned __addr_ok() definition ARM: get rid of horrible *(unsigned int *)(regs + 1) ARM: introduce svc_pt_regs structure ...
This commit is contained in:
commit
b5f00d18cc
|
@ -1186,6 +1186,60 @@ config ARM_ERRATA_773022
|
|||
loop buffer may deliver incorrect instructions. This
|
||||
workaround disables the loop buffer to avoid the erratum.
|
||||
|
||||
config ARM_ERRATA_818325_852422
|
||||
bool "ARM errata: A12: some seqs of opposed cond code instrs => deadlock or corruption"
|
||||
depends on CPU_V7
|
||||
help
|
||||
This option enables the workaround for:
|
||||
- Cortex-A12 818325: Execution of an UNPREDICTABLE STR or STM
|
||||
instruction might deadlock. Fixed in r0p1.
|
||||
- Cortex-A12 852422: Execution of a sequence of instructions might
|
||||
lead to either a data corruption or a CPU deadlock. Not fixed in
|
||||
any Cortex-A12 cores yet.
|
||||
This workaround for all both errata involves setting bit[12] of the
|
||||
Feature Register. This bit disables an optimisation applied to a
|
||||
sequence of 2 instructions that use opposing condition codes.
|
||||
|
||||
config ARM_ERRATA_821420
|
||||
bool "ARM errata: A12: sequence of VMOV to core registers might lead to a dead lock"
|
||||
depends on CPU_V7
|
||||
help
|
||||
This option enables the workaround for the 821420 Cortex-A12
|
||||
(all revs) erratum. In very rare timing conditions, a sequence
|
||||
of VMOV to Core registers instructions, for which the second
|
||||
one is in the shadow of a branch or abort, can lead to a
|
||||
deadlock when the VMOV instructions are issued out-of-order.
|
||||
|
||||
config ARM_ERRATA_825619
|
||||
bool "ARM errata: A12: DMB NSHST/ISHST mixed ... might cause deadlock"
|
||||
depends on CPU_V7
|
||||
help
|
||||
This option enables the workaround for the 825619 Cortex-A12
|
||||
(all revs) erratum. Within rare timing constraints, executing a
|
||||
DMB NSHST or DMB ISHST instruction followed by a mix of Cacheable
|
||||
and Device/Strongly-Ordered loads and stores might cause deadlock
|
||||
|
||||
config ARM_ERRATA_852421
|
||||
bool "ARM errata: A17: DMB ST might fail to create order between stores"
|
||||
depends on CPU_V7
|
||||
help
|
||||
This option enables the workaround for the 852421 Cortex-A17
|
||||
(r1p0, r1p1, r1p2) erratum. Under very rare timing conditions,
|
||||
execution of a DMB ST instruction might fail to properly order
|
||||
stores from GroupA and stores from GroupB.
|
||||
|
||||
config ARM_ERRATA_852423
|
||||
bool "ARM errata: A17: some seqs of opposed cond code instrs => deadlock or corruption"
|
||||
depends on CPU_V7
|
||||
help
|
||||
This option enables the workaround for:
|
||||
- Cortex-A17 852423: Execution of a sequence of instructions might
|
||||
lead to either a data corruption or a CPU deadlock. Not fixed in
|
||||
any Cortex-A17 cores yet.
|
||||
This is identical to Cortex-A12 erratum 852422. It is a separate
|
||||
config option from the A12 erratum due to the way errata are checked
|
||||
for and handled.
|
||||
|
||||
endmenu
|
||||
|
||||
source "arch/arm/common/Kconfig"
|
||||
|
|
|
@ -327,6 +327,7 @@ zImage: Image
|
|||
|
||||
$(BOOT_TARGETS): vmlinux
|
||||
$(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@
|
||||
@$(kecho) ' Kernel: $(boot)/$@ is ready'
|
||||
|
||||
$(INSTALL_TARGETS):
|
||||
$(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $@
|
||||
|
|
|
@ -31,7 +31,7 @@ ifeq ($(CONFIG_XIP_KERNEL),y)
|
|||
|
||||
$(obj)/xipImage: vmlinux FORCE
|
||||
$(call if_changed,objcopy)
|
||||
@$(kecho) ' Kernel: $@ is ready (physical address: $(CONFIG_XIP_PHYS_ADDR))'
|
||||
@$(kecho) ' Physical Address of xipImage: $(CONFIG_XIP_PHYS_ADDR)'
|
||||
|
||||
$(obj)/Image $(obj)/zImage: FORCE
|
||||
@echo 'Kernel configured for XIP (CONFIG_XIP_KERNEL=y)'
|
||||
|
@ -46,14 +46,12 @@ $(obj)/xipImage: FORCE
|
|||
|
||||
$(obj)/Image: vmlinux FORCE
|
||||
$(call if_changed,objcopy)
|
||||
@$(kecho) ' Kernel: $@ is ready'
|
||||
|
||||
$(obj)/compressed/vmlinux: $(obj)/Image FORCE
|
||||
$(Q)$(MAKE) $(build)=$(obj)/compressed $@
|
||||
|
||||
$(obj)/zImage: $(obj)/compressed/vmlinux FORCE
|
||||
$(call if_changed,objcopy)
|
||||
@$(kecho) ' Kernel: $@ is ready'
|
||||
|
||||
endif
|
||||
|
||||
|
@ -78,14 +76,12 @@ fi
|
|||
$(obj)/uImage: $(obj)/zImage FORCE
|
||||
@$(check_for_multiple_loadaddr)
|
||||
$(call if_changed,uimage)
|
||||
@$(kecho) ' Image $@ is ready'
|
||||
|
||||
$(obj)/bootp/bootp: $(obj)/zImage initrd FORCE
|
||||
$(Q)$(MAKE) $(build)=$(obj)/bootp $@
|
||||
|
||||
$(obj)/bootpImage: $(obj)/bootp/bootp FORCE
|
||||
$(call if_changed,objcopy)
|
||||
@$(kecho) ' Kernel: $@ is ready'
|
||||
|
||||
PHONY += initrd install zinstall uinstall
|
||||
initrd:
|
||||
|
|
|
@ -480,13 +480,13 @@ THUMB( orr \reg , \reg , #PSR_T_BIT )
|
|||
.macro uaccess_save, tmp
|
||||
#ifdef CONFIG_CPU_SW_DOMAIN_PAN
|
||||
mrc p15, 0, \tmp, c3, c0, 0
|
||||
str \tmp, [sp, #S_FRAME_SIZE]
|
||||
str \tmp, [sp, #SVC_DACR]
|
||||
#endif
|
||||
.endm
|
||||
|
||||
.macro uaccess_restore
|
||||
#ifdef CONFIG_CPU_SW_DOMAIN_PAN
|
||||
ldr r0, [sp, #S_FRAME_SIZE]
|
||||
ldr r0, [sp, #SVC_DACR]
|
||||
mcr p15, 0, r0, c3, c0, 0
|
||||
#endif
|
||||
.endm
|
||||
|
|
|
@ -44,9 +44,7 @@ extern void arm_heavy_mb(void);
|
|||
#define __arm_heavy_mb(x...) dsb(x)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ARCH_HAS_BARRIERS
|
||||
#include <mach/barriers.h>
|
||||
#elif defined(CONFIG_ARM_DMA_MEM_BUFFERABLE) || defined(CONFIG_SMP)
|
||||
#if defined(CONFIG_ARM_DMA_MEM_BUFFERABLE) || defined(CONFIG_SMP)
|
||||
#define mb() __arm_heavy_mb()
|
||||
#define rmb() dsb()
|
||||
#define wmb() __arm_heavy_mb(st)
|
||||
|
|
|
@ -10,8 +10,8 @@
|
|||
#include <asm/param.h> /* HZ */
|
||||
|
||||
#define MAX_UDELAY_MS 2
|
||||
#define UDELAY_MULT ((UL(2199023) * HZ) >> 11)
|
||||
#define UDELAY_SHIFT 30
|
||||
#define UDELAY_MULT UL(2047 * HZ + 483648 * HZ / 1000000)
|
||||
#define UDELAY_SHIFT 31
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
|
@ -34,7 +34,7 @@ extern struct arm_delay_ops {
|
|||
* it, it means that you're calling udelay() with an out of range value.
|
||||
*
|
||||
* With currently imposed limits, this means that we support a max delay
|
||||
* of 2000us. Further limits: HZ<=1000 and bogomips<=3355
|
||||
* of 2000us. Further limits: HZ<=1000
|
||||
*/
|
||||
extern void __bad_udelay(void);
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
#define fd_outb(val,port) \
|
||||
do { \
|
||||
if ((port) == FD_DOR) \
|
||||
if ((port) == (u32)FD_DOR) \
|
||||
fd_setdor((val)); \
|
||||
else \
|
||||
outb((val),(port)); \
|
||||
|
|
|
@ -13,10 +13,20 @@
|
|||
#include <uapi/asm/ptrace.h>
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
#include <linux/types.h>
|
||||
|
||||
struct pt_regs {
|
||||
unsigned long uregs[18];
|
||||
};
|
||||
|
||||
struct svc_pt_regs {
|
||||
struct pt_regs regs;
|
||||
u32 dacr;
|
||||
u32 addr_limit;
|
||||
};
|
||||
|
||||
#define to_svc_pt_regs(r) container_of(r, struct svc_pt_regs, regs)
|
||||
|
||||
#define user_mode(regs) \
|
||||
(((regs)->ARM_cpsr & 0xf) == 0)
|
||||
|
||||
|
|
|
@ -104,14 +104,6 @@ static inline void set_fs(mm_segment_t fs)
|
|||
|
||||
#define segment_eq(a, b) ((a) == (b))
|
||||
|
||||
#define __addr_ok(addr) ({ \
|
||||
unsigned long flag; \
|
||||
__asm__("cmp %2, %0; movlo %0, #0" \
|
||||
: "=&r" (flag) \
|
||||
: "0" (current_thread_info()->addr_limit), "r" (addr) \
|
||||
: "cc"); \
|
||||
(flag == 0); })
|
||||
|
||||
/* We use 33-bit arithmetic here... */
|
||||
#define __range_ok(addr, size) ({ \
|
||||
unsigned long flag, roksum; \
|
||||
|
@ -238,47 +230,21 @@ extern int __put_user_2(void *, unsigned int);
|
|||
extern int __put_user_4(void *, unsigned int);
|
||||
extern int __put_user_8(void *, unsigned long long);
|
||||
|
||||
#define __put_user_x(__r2, __p, __e, __l, __s) \
|
||||
#define __put_user_check(__pu_val, __ptr, __err, __s) \
|
||||
({ \
|
||||
unsigned long __limit = current_thread_info()->addr_limit - 1; \
|
||||
register typeof(__pu_val) __r2 asm("r2") = __pu_val; \
|
||||
register const void __user *__p asm("r0") = __ptr; \
|
||||
register unsigned long __l asm("r1") = __limit; \
|
||||
register int __e asm("r0"); \
|
||||
__asm__ __volatile__ ( \
|
||||
__asmeq("%0", "r0") __asmeq("%2", "r2") \
|
||||
__asmeq("%3", "r1") \
|
||||
"bl __put_user_" #__s \
|
||||
: "=&r" (__e) \
|
||||
: "0" (__p), "r" (__r2), "r" (__l) \
|
||||
: "ip", "lr", "cc")
|
||||
|
||||
#define __put_user_check(x, p) \
|
||||
({ \
|
||||
unsigned long __limit = current_thread_info()->addr_limit - 1; \
|
||||
const typeof(*(p)) __user *__tmp_p = (p); \
|
||||
register const typeof(*(p)) __r2 asm("r2") = (x); \
|
||||
register const typeof(*(p)) __user *__p asm("r0") = __tmp_p; \
|
||||
register unsigned long __l asm("r1") = __limit; \
|
||||
register int __e asm("r0"); \
|
||||
unsigned int __ua_flags = uaccess_save_and_enable(); \
|
||||
switch (sizeof(*(__p))) { \
|
||||
case 1: \
|
||||
__put_user_x(__r2, __p, __e, __l, 1); \
|
||||
break; \
|
||||
case 2: \
|
||||
__put_user_x(__r2, __p, __e, __l, 2); \
|
||||
break; \
|
||||
case 4: \
|
||||
__put_user_x(__r2, __p, __e, __l, 4); \
|
||||
break; \
|
||||
case 8: \
|
||||
__put_user_x(__r2, __p, __e, __l, 8); \
|
||||
break; \
|
||||
default: __e = __put_user_bad(); break; \
|
||||
} \
|
||||
uaccess_restore(__ua_flags); \
|
||||
__e; \
|
||||
})
|
||||
|
||||
#define put_user(x, p) \
|
||||
({ \
|
||||
might_fault(); \
|
||||
__put_user_check(x, p); \
|
||||
: "ip", "lr", "cc"); \
|
||||
__err = __e; \
|
||||
})
|
||||
|
||||
#else /* CONFIG_MMU */
|
||||
|
@ -298,7 +264,7 @@ static inline void set_fs(mm_segment_t fs)
|
|||
}
|
||||
|
||||
#define get_user(x, p) __get_user(x, p)
|
||||
#define put_user(x, p) __put_user(x, p)
|
||||
#define __put_user_check __put_user_nocheck
|
||||
|
||||
#endif /* CONFIG_MMU */
|
||||
|
||||
|
@ -389,36 +355,54 @@ do { \
|
|||
#define __get_user_asm_word(x, addr, err) \
|
||||
__get_user_asm(x, addr, err, ldr)
|
||||
|
||||
|
||||
#define __put_user_switch(x, ptr, __err, __fn) \
|
||||
do { \
|
||||
const __typeof__(*(ptr)) __user *__pu_ptr = (ptr); \
|
||||
__typeof__(*(ptr)) __pu_val = (x); \
|
||||
unsigned int __ua_flags; \
|
||||
might_fault(); \
|
||||
__ua_flags = uaccess_save_and_enable(); \
|
||||
switch (sizeof(*(ptr))) { \
|
||||
case 1: __fn(__pu_val, __pu_ptr, __err, 1); break; \
|
||||
case 2: __fn(__pu_val, __pu_ptr, __err, 2); break; \
|
||||
case 4: __fn(__pu_val, __pu_ptr, __err, 4); break; \
|
||||
case 8: __fn(__pu_val, __pu_ptr, __err, 8); break; \
|
||||
default: __err = __put_user_bad(); break; \
|
||||
} \
|
||||
uaccess_restore(__ua_flags); \
|
||||
} while (0)
|
||||
|
||||
#define put_user(x, ptr) \
|
||||
({ \
|
||||
int __pu_err = 0; \
|
||||
__put_user_switch((x), (ptr), __pu_err, __put_user_check); \
|
||||
__pu_err; \
|
||||
})
|
||||
|
||||
#define __put_user(x, ptr) \
|
||||
({ \
|
||||
long __pu_err = 0; \
|
||||
__put_user_err((x), (ptr), __pu_err); \
|
||||
__put_user_switch((x), (ptr), __pu_err, __put_user_nocheck); \
|
||||
__pu_err; \
|
||||
})
|
||||
|
||||
#define __put_user_error(x, ptr, err) \
|
||||
({ \
|
||||
__put_user_err((x), (ptr), err); \
|
||||
__put_user_switch((x), (ptr), (err), __put_user_nocheck); \
|
||||
(void) 0; \
|
||||
})
|
||||
|
||||
#define __put_user_err(x, ptr, err) \
|
||||
do { \
|
||||
unsigned long __pu_addr = (unsigned long)(ptr); \
|
||||
unsigned int __ua_flags; \
|
||||
__typeof__(*(ptr)) __pu_val = (x); \
|
||||
__chk_user_ptr(ptr); \
|
||||
might_fault(); \
|
||||
__ua_flags = uaccess_save_and_enable(); \
|
||||
switch (sizeof(*(ptr))) { \
|
||||
case 1: __put_user_asm_byte(__pu_val, __pu_addr, err); break; \
|
||||
case 2: __put_user_asm_half(__pu_val, __pu_addr, err); break; \
|
||||
case 4: __put_user_asm_word(__pu_val, __pu_addr, err); break; \
|
||||
case 8: __put_user_asm_dword(__pu_val, __pu_addr, err); break; \
|
||||
default: __put_user_bad(); \
|
||||
} \
|
||||
uaccess_restore(__ua_flags); \
|
||||
} while (0)
|
||||
#define __put_user_nocheck(x, __pu_ptr, __err, __size) \
|
||||
do { \
|
||||
unsigned long __pu_addr = (unsigned long)__pu_ptr; \
|
||||
__put_user_nocheck_##__size(x, __pu_addr, __err); \
|
||||
} while (0)
|
||||
|
||||
#define __put_user_nocheck_1 __put_user_asm_byte
|
||||
#define __put_user_nocheck_2 __put_user_asm_half
|
||||
#define __put_user_nocheck_4 __put_user_asm_word
|
||||
#define __put_user_nocheck_8 __put_user_asm_dword
|
||||
|
||||
#define __put_user_asm(x, __pu_addr, err, instr) \
|
||||
__asm__ __volatile__( \
|
||||
|
|
|
@ -107,7 +107,10 @@ int main(void)
|
|||
DEFINE(S_PC, offsetof(struct pt_regs, ARM_pc));
|
||||
DEFINE(S_PSR, offsetof(struct pt_regs, ARM_cpsr));
|
||||
DEFINE(S_OLD_R0, offsetof(struct pt_regs, ARM_ORIG_r0));
|
||||
DEFINE(S_FRAME_SIZE, sizeof(struct pt_regs));
|
||||
DEFINE(PT_REGS_SIZE, sizeof(struct pt_regs));
|
||||
DEFINE(SVC_DACR, offsetof(struct svc_pt_regs, dacr));
|
||||
DEFINE(SVC_ADDR_LIMIT, offsetof(struct svc_pt_regs, addr_limit));
|
||||
DEFINE(SVC_REGS_SIZE, sizeof(struct svc_pt_regs));
|
||||
BLANK();
|
||||
#ifdef CONFIG_CACHE_L2X0
|
||||
DEFINE(L2X0_R_PHY_BASE, offsetof(struct l2x0_regs, phy_base));
|
||||
|
|
|
@ -47,18 +47,13 @@ int arm_cpuidle_simple_enter(struct cpuidle_device *dev,
|
|||
* This function calls the underlying arch specific low level PM code as
|
||||
* registered at the init time.
|
||||
*
|
||||
* Returns -EOPNOTSUPP if no suspend callback is defined, the result of the
|
||||
* callback otherwise.
|
||||
* Returns the result of the suspend callback.
|
||||
*/
|
||||
int arm_cpuidle_suspend(int index)
|
||||
{
|
||||
int ret = -EOPNOTSUPP;
|
||||
int cpu = smp_processor_id();
|
||||
|
||||
if (cpuidle_ops[cpu].suspend)
|
||||
ret = cpuidle_ops[cpu].suspend(index);
|
||||
|
||||
return ret;
|
||||
return cpuidle_ops[cpu].suspend(index);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -92,7 +87,8 @@ static const struct cpuidle_ops *__init arm_cpuidle_get_ops(const char *method)
|
|||
* process.
|
||||
*
|
||||
* Return 0 on sucess, -ENOENT if no 'enable-method' is defined, -EOPNOTSUPP if
|
||||
* no cpuidle_ops is registered for the 'enable-method'.
|
||||
* no cpuidle_ops is registered for the 'enable-method', or if either init or
|
||||
* suspend callback isn't defined.
|
||||
*/
|
||||
static int __init arm_cpuidle_read_ops(struct device_node *dn, int cpu)
|
||||
{
|
||||
|
@ -110,6 +106,12 @@ static int __init arm_cpuidle_read_ops(struct device_node *dn, int cpu)
|
|||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (!ops->init || !ops->suspend) {
|
||||
pr_warn("cpuidle_ops '%s': no init or suspend callback\n",
|
||||
enable_method);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
cpuidle_ops[cpu] = *ops; /* structure copy */
|
||||
|
||||
pr_notice("cpuidle: enable-method property '%s'"
|
||||
|
@ -129,7 +131,8 @@ static int __init arm_cpuidle_read_ops(struct device_node *dn, int cpu)
|
|||
* Returns:
|
||||
* 0 on success,
|
||||
* -ENODEV if it fails to find the cpu node in the device tree,
|
||||
* -EOPNOTSUPP if it does not find a registered cpuidle_ops for this cpu,
|
||||
* -EOPNOTSUPP if it does not find a registered and valid cpuidle_ops for
|
||||
* this cpu,
|
||||
* -ENOENT if it fails to find an 'enable-method' property,
|
||||
* -ENXIO if the HW reports a failure or a misconfiguration,
|
||||
* -ENOMEM if the HW report an memory allocation failure
|
||||
|
@ -143,7 +146,7 @@ int __init arm_cpuidle_init(int cpu)
|
|||
return -ENODEV;
|
||||
|
||||
ret = arm_cpuidle_read_ops(cpu_node, cpu);
|
||||
if (!ret && cpuidle_ops[cpu].init)
|
||||
if (!ret)
|
||||
ret = cpuidle_ops[cpu].init(cpu_node, cpu);
|
||||
|
||||
of_node_put(cpu_node);
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <asm/cputype.h>
|
||||
#include <asm/setup.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/prom.h>
|
||||
#include <asm/smp_plat.h>
|
||||
#include <asm/mach/arch.h>
|
||||
#include <asm/mach-types.h>
|
||||
|
@ -213,6 +214,8 @@ const struct machine_desc * __init setup_machine_fdt(unsigned int dt_phys)
|
|||
|
||||
#if defined(CONFIG_ARCH_MULTIPLATFORM) || defined(CONFIG_ARM_SINGLE_ARMV7M)
|
||||
DT_MACHINE_START(GENERIC_DT, "Generic DT based system")
|
||||
.l2c_aux_val = 0x0,
|
||||
.l2c_aux_mask = ~0x0,
|
||||
MACHINE_END
|
||||
|
||||
mdesc_best = &__mach_desc_GENERIC_DT;
|
||||
|
|
|
@ -92,7 +92,7 @@
|
|||
* Invalid mode handlers
|
||||
*/
|
||||
.macro inv_entry, reason
|
||||
sub sp, sp, #S_FRAME_SIZE
|
||||
sub sp, sp, #PT_REGS_SIZE
|
||||
ARM( stmib sp, {r1 - lr} )
|
||||
THUMB( stmia sp, {r0 - r12} )
|
||||
THUMB( str sp, [sp, #S_SP] )
|
||||
|
@ -152,7 +152,7 @@ ENDPROC(__und_invalid)
|
|||
.macro svc_entry, stack_hole=0, trace=1, uaccess=1
|
||||
UNWIND(.fnstart )
|
||||
UNWIND(.save {r0 - pc} )
|
||||
sub sp, sp, #(S_FRAME_SIZE + 8 + \stack_hole - 4)
|
||||
sub sp, sp, #(SVC_REGS_SIZE + \stack_hole - 4)
|
||||
#ifdef CONFIG_THUMB2_KERNEL
|
||||
SPFIX( str r0, [sp] ) @ temporarily saved
|
||||
SPFIX( mov r0, sp )
|
||||
|
@ -167,7 +167,7 @@ ENDPROC(__und_invalid)
|
|||
ldmia r0, {r3 - r5}
|
||||
add r7, sp, #S_SP - 4 @ here for interlock avoidance
|
||||
mov r6, #-1 @ "" "" "" ""
|
||||
add r2, sp, #(S_FRAME_SIZE + 8 + \stack_hole - 4)
|
||||
add r2, sp, #(SVC_REGS_SIZE + \stack_hole - 4)
|
||||
SPFIX( addeq r2, r2, #4 )
|
||||
str r3, [sp, #-4]! @ save the "real" r0 copied
|
||||
@ from the exception stack
|
||||
|
@ -185,6 +185,12 @@ ENDPROC(__und_invalid)
|
|||
@
|
||||
stmia r7, {r2 - r6}
|
||||
|
||||
get_thread_info tsk
|
||||
ldr r0, [tsk, #TI_ADDR_LIMIT]
|
||||
mov r1, #TASK_SIZE
|
||||
str r1, [tsk, #TI_ADDR_LIMIT]
|
||||
str r0, [sp, #SVC_ADDR_LIMIT]
|
||||
|
||||
uaccess_save r0
|
||||
.if \uaccess
|
||||
uaccess_disable r0
|
||||
|
@ -213,7 +219,6 @@ __irq_svc:
|
|||
irq_handler
|
||||
|
||||
#ifdef CONFIG_PREEMPT
|
||||
get_thread_info tsk
|
||||
ldr r8, [tsk, #TI_PREEMPT] @ get preempt count
|
||||
ldr r0, [tsk, #TI_FLAGS] @ get flags
|
||||
teq r8, #0 @ if preempt count != 0
|
||||
|
@ -366,17 +371,17 @@ ENDPROC(__fiq_abt)
|
|||
/*
|
||||
* User mode handlers
|
||||
*
|
||||
* EABI note: sp_svc is always 64-bit aligned here, so should S_FRAME_SIZE
|
||||
* EABI note: sp_svc is always 64-bit aligned here, so should PT_REGS_SIZE
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5) && (S_FRAME_SIZE & 7)
|
||||
#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5) && (PT_REGS_SIZE & 7)
|
||||
#error "sizeof(struct pt_regs) must be a multiple of 8"
|
||||
#endif
|
||||
|
||||
.macro usr_entry, trace=1, uaccess=1
|
||||
UNWIND(.fnstart )
|
||||
UNWIND(.cantunwind ) @ don't unwind the user space
|
||||
sub sp, sp, #S_FRAME_SIZE
|
||||
sub sp, sp, #PT_REGS_SIZE
|
||||
ARM( stmib sp, {r1 - r12} )
|
||||
THUMB( stmia sp, {r0 - r12} )
|
||||
|
||||
|
|
|
@ -145,7 +145,7 @@ ENTRY(vector_swi)
|
|||
#ifdef CONFIG_CPU_V7M
|
||||
v7m_exception_entry
|
||||
#else
|
||||
sub sp, sp, #S_FRAME_SIZE
|
||||
sub sp, sp, #PT_REGS_SIZE
|
||||
stmia sp, {r0 - r12} @ Calling r0 - r12
|
||||
ARM( add r8, sp, #S_PC )
|
||||
ARM( stmdb r8, {sp, lr}^ ) @ Calling sp, lr
|
||||
|
|
|
@ -90,7 +90,7 @@
|
|||
@ Linux expects to have irqs off. Do it here before taking stack space
|
||||
cpsid i
|
||||
|
||||
sub sp, #S_FRAME_SIZE-S_IP
|
||||
sub sp, #PT_REGS_SIZE-S_IP
|
||||
stmdb sp!, {r0-r11}
|
||||
|
||||
@ load saved r12, lr, return address and xPSR.
|
||||
|
@ -160,7 +160,7 @@
|
|||
ldmia sp!, {r0-r11}
|
||||
|
||||
@ restore main sp
|
||||
add sp, sp, #S_FRAME_SIZE-S_IP
|
||||
add sp, sp, #PT_REGS_SIZE-S_IP
|
||||
|
||||
cpsie i
|
||||
bx lr
|
||||
|
@ -215,7 +215,9 @@
|
|||
blne trace_hardirqs_off
|
||||
#endif
|
||||
.endif
|
||||
ldr r1, [sp, #SVC_ADDR_LIMIT]
|
||||
uaccess_restore
|
||||
str r1, [tsk, #TI_ADDR_LIMIT]
|
||||
|
||||
#ifndef CONFIG_THUMB2_KERNEL
|
||||
@ ARM mode SVC restore
|
||||
|
@ -259,7 +261,9 @@
|
|||
@ on the stack remains correct).
|
||||
@
|
||||
.macro svc_exit_via_fiq
|
||||
ldr r1, [sp, #SVC_ADDR_LIMIT]
|
||||
uaccess_restore
|
||||
str r1, [tsk, #TI_ADDR_LIMIT]
|
||||
#ifndef CONFIG_THUMB2_KERNEL
|
||||
@ ARM mode restore
|
||||
mov r0, sp
|
||||
|
@ -307,7 +311,7 @@
|
|||
.endif
|
||||
mov r0, r0 @ ARMv5T and earlier require a nop
|
||||
@ after ldm {}^
|
||||
add sp, sp, #\offset + S_FRAME_SIZE
|
||||
add sp, sp, #\offset + PT_REGS_SIZE
|
||||
movs pc, lr @ return & move spsr_svc into cpsr
|
||||
#elif defined(CONFIG_CPU_V7M)
|
||||
@ V7M restore.
|
||||
|
@ -334,7 +338,7 @@
|
|||
.else
|
||||
ldmdb sp, {r0 - r12} @ get calling r0 - r12
|
||||
.endif
|
||||
add sp, sp, #S_FRAME_SIZE - S_SP
|
||||
add sp, sp, #PT_REGS_SIZE - S_SP
|
||||
movs pc, lr @ return & move spsr_svc into cpsr
|
||||
#endif /* !CONFIG_THUMB2_KERNEL */
|
||||
.endm
|
||||
|
|
|
@ -73,7 +73,7 @@ __irq_entry:
|
|||
@ correctness they don't need to be restored. So only r8-r11 must be
|
||||
@ restored here. The easiest way to do so is to restore r0-r7, too.
|
||||
ldmia sp!, {r0-r11}
|
||||
add sp, #S_FRAME_SIZE-S_IP
|
||||
add sp, #PT_REGS_SIZE-S_IP
|
||||
cpsie i
|
||||
bx lr
|
||||
ENDPROC(__irq_entry)
|
||||
|
|
|
@ -96,19 +96,23 @@ void __show_regs(struct pt_regs *regs)
|
|||
unsigned long flags;
|
||||
char buf[64];
|
||||
#ifndef CONFIG_CPU_V7M
|
||||
unsigned int domain;
|
||||
unsigned int domain, fs;
|
||||
#ifdef CONFIG_CPU_SW_DOMAIN_PAN
|
||||
/*
|
||||
* Get the domain register for the parent context. In user
|
||||
* mode, we don't save the DACR, so lets use what it should
|
||||
* be. For other modes, we place it after the pt_regs struct.
|
||||
*/
|
||||
if (user_mode(regs))
|
||||
if (user_mode(regs)) {
|
||||
domain = DACR_UACCESS_ENABLE;
|
||||
else
|
||||
domain = *(unsigned int *)(regs + 1);
|
||||
fs = get_fs();
|
||||
} else {
|
||||
domain = to_svc_pt_regs(regs)->dacr;
|
||||
fs = to_svc_pt_regs(regs)->addr_limit;
|
||||
}
|
||||
#else
|
||||
domain = get_domain();
|
||||
fs = get_fs();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
@ -144,7 +148,7 @@ void __show_regs(struct pt_regs *regs)
|
|||
if ((domain & domain_mask(DOMAIN_USER)) ==
|
||||
domain_val(DOMAIN_USER, DOMAIN_NOACCESS))
|
||||
segment = "none";
|
||||
else if (get_fs() == get_ds())
|
||||
else if (fs == get_ds())
|
||||
segment = "kernel";
|
||||
else
|
||||
segment = "user";
|
||||
|
|
|
@ -844,7 +844,7 @@ static void __init request_standard_resources(const struct machine_desc *mdesc)
|
|||
struct resource *res;
|
||||
|
||||
kernel_code.start = virt_to_phys(_text);
|
||||
kernel_code.end = virt_to_phys(_etext - 1);
|
||||
kernel_code.end = virt_to_phys(__init_begin - 1);
|
||||
kernel_data.start = virt_to_phys(_sdata);
|
||||
kernel_data.end = virt_to_phys(_end - 1);
|
||||
|
||||
|
|
|
@ -93,17 +93,53 @@ void erratum_a15_798181_init(void)
|
|||
unsigned int revidr = read_cpuid(CPUID_REVIDR);
|
||||
|
||||
/* Brahma-B15 r0p0..r0p2 affected
|
||||
* Cortex-A15 r0p0..r3p2 w/o ECO fix affected */
|
||||
if ((midr & 0xff0ffff0) == 0x420f00f0 && midr <= 0x420f00f2)
|
||||
* Cortex-A15 r0p0..r3p3 w/o ECO fix affected
|
||||
* Fixes applied to A15 with respect to the revision and revidr are:
|
||||
*
|
||||
* r0p0-r2p1: No fixes applied
|
||||
* r2p2,r2p3:
|
||||
* REVIDR[4]: 798181 Moving a virtual page that is being accessed
|
||||
* by an active process can lead to unexpected behavior
|
||||
* REVIDR[9]: Not defined
|
||||
* r2p4,r3p0,r3p1,r3p2:
|
||||
* REVIDR[4]: 798181 Moving a virtual page that is being accessed
|
||||
* by an active process can lead to unexpected behavior
|
||||
* REVIDR[9]: 798181 Moving a virtual page that is being accessed
|
||||
* by an active process can lead to unexpected behavior
|
||||
* - This is an update to a previously released ECO.
|
||||
* r3p3:
|
||||
* REVIDR[4]: Reserved
|
||||
* REVIDR[9]: 798181 Moving a virtual page that is being accessed
|
||||
* by an active process can lead to unexpected behavior
|
||||
* - This is an update to a previously released ECO.
|
||||
*
|
||||
* Handling:
|
||||
* REVIDR[9] set -> No WA
|
||||
* REVIDR[4] set, REVIDR[9] cleared -> Partial WA
|
||||
* Both cleared -> Full WA
|
||||
*/
|
||||
if ((midr & 0xff0ffff0) == 0x420f00f0 && midr <= 0x420f00f2) {
|
||||
erratum_a15_798181_handler = erratum_a15_798181_broadcast;
|
||||
else if ((midr & 0xff0ffff0) == 0x410fc0f0 && midr <= 0x413fc0f2 &&
|
||||
(revidr & 0x210) != 0x210) {
|
||||
} else if ((midr & 0xff0ffff0) == 0x410fc0f0 && midr < 0x412fc0f2) {
|
||||
erratum_a15_798181_handler = erratum_a15_798181_broadcast;
|
||||
} else if ((midr & 0xff0ffff0) == 0x410fc0f0 && midr < 0x412fc0f4) {
|
||||
if (revidr & 0x10)
|
||||
erratum_a15_798181_handler =
|
||||
erratum_a15_798181_partial;
|
||||
else
|
||||
erratum_a15_798181_handler =
|
||||
erratum_a15_798181_broadcast;
|
||||
} else if ((midr & 0xff0ffff0) == 0x410fc0f0 && midr < 0x413fc0f3) {
|
||||
if ((revidr & 0x210) == 0)
|
||||
erratum_a15_798181_handler =
|
||||
erratum_a15_798181_broadcast;
|
||||
else if (revidr & 0x10)
|
||||
erratum_a15_798181_handler =
|
||||
erratum_a15_798181_partial;
|
||||
} else if ((midr & 0xff0ffff0) == 0x410fc0f0 && midr < 0x414fc0f0) {
|
||||
if ((revidr & 0x200) == 0)
|
||||
erratum_a15_798181_handler =
|
||||
erratum_a15_798181_partial;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -125,6 +125,8 @@ SECTIONS
|
|||
#ifdef CONFIG_DEBUG_ALIGN_RODATA
|
||||
. = ALIGN(1<<SECTION_SHIFT);
|
||||
#endif
|
||||
_etext = .; /* End of text section */
|
||||
|
||||
RO_DATA(PAGE_SIZE)
|
||||
|
||||
. = ALIGN(4);
|
||||
|
@ -155,8 +157,6 @@ SECTIONS
|
|||
|
||||
NOTES
|
||||
|
||||
_etext = .; /* End of text and rodata section */
|
||||
|
||||
#ifdef CONFIG_DEBUG_RODATA
|
||||
. = ALIGN(1<<SECTION_SHIFT);
|
||||
#else
|
||||
|
|
|
@ -29,7 +29,10 @@ else
|
|||
lib-y += io-readsw-armv4.o io-writesw-armv4.o
|
||||
endif
|
||||
|
||||
lib-$(CONFIG_ARCH_RPC) += ecard.o io-acorn.o floppydma.o
|
||||
ifeq ($(CONFIG_ARCH_RPC),y)
|
||||
lib-y += ecard.o io-acorn.o floppydma.o
|
||||
AFLAGS_delay-loop.o += -march=armv4
|
||||
endif
|
||||
|
||||
$(obj)/csumpartialcopy.o: $(obj)/csumpartialcopygeneric.S
|
||||
$(obj)/csumpartialcopyuser.o: $(obj)/csumpartialcopygeneric.S
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <linux/linkage.h>
|
||||
#include <asm/assembler.h>
|
||||
#include <asm/delay.h>
|
||||
|
||||
.text
|
||||
|
||||
.LC0: .word loops_per_jiffy
|
||||
|
@ -17,7 +18,6 @@
|
|||
|
||||
/*
|
||||
* r0 <= 2000
|
||||
* lpj <= 0x01ffffff (max. 3355 bogomips)
|
||||
* HZ <= 1000
|
||||
*/
|
||||
|
||||
|
@ -25,16 +25,11 @@ ENTRY(__loop_udelay)
|
|||
ldr r2, .LC1
|
||||
mul r0, r2, r0
|
||||
ENTRY(__loop_const_udelay) @ 0 <= r0 <= 0x7fffff06
|
||||
mov r1, #-1
|
||||
ldr r2, .LC0
|
||||
ldr r2, [r2] @ max = 0x01ffffff
|
||||
add r0, r0, r1, lsr #32-14
|
||||
mov r0, r0, lsr #14 @ max = 0x0001ffff
|
||||
add r2, r2, r1, lsr #32-10
|
||||
mov r2, r2, lsr #10 @ max = 0x00007fff
|
||||
mul r0, r2, r0 @ max = 2^32-1
|
||||
add r0, r0, r1, lsr #32-6
|
||||
movs r0, r0, lsr #6
|
||||
ldr r2, [r2]
|
||||
umull r1, r0, r2, r0
|
||||
adds r1, r1, #0xffffffff
|
||||
adcs r0, r0, r0
|
||||
reteq lr
|
||||
|
||||
/*
|
||||
|
|
|
@ -1025,12 +1025,6 @@ config ARM_DMA_MEM_BUFFERABLE
|
|||
|
||||
You are recommended say 'Y' here and debug any affected drivers.
|
||||
|
||||
config ARCH_HAS_BARRIERS
|
||||
bool
|
||||
help
|
||||
This option allows the use of custom mandatory barriers
|
||||
included via the mach/barriers.h file.
|
||||
|
||||
config ARM_HEAVY_MB
|
||||
bool
|
||||
|
||||
|
|
|
@ -49,6 +49,7 @@ struct arm_dma_alloc_args {
|
|||
pgprot_t prot;
|
||||
const void *caller;
|
||||
bool want_vaddr;
|
||||
int coherent_flag;
|
||||
};
|
||||
|
||||
struct arm_dma_free_args {
|
||||
|
@ -59,6 +60,9 @@ struct arm_dma_free_args {
|
|||
bool want_vaddr;
|
||||
};
|
||||
|
||||
#define NORMAL 0
|
||||
#define COHERENT 1
|
||||
|
||||
struct arm_dma_allocator {
|
||||
void *(*alloc)(struct arm_dma_alloc_args *args,
|
||||
struct page **ret_page);
|
||||
|
@ -272,7 +276,7 @@ static u64 get_coherent_dma_mask(struct device *dev)
|
|||
return mask;
|
||||
}
|
||||
|
||||
static void __dma_clear_buffer(struct page *page, size_t size)
|
||||
static void __dma_clear_buffer(struct page *page, size_t size, int coherent_flag)
|
||||
{
|
||||
/*
|
||||
* Ensure that the allocated pages are zeroed, and that any data
|
||||
|
@ -284,25 +288,30 @@ static void __dma_clear_buffer(struct page *page, size_t size)
|
|||
while (size > 0) {
|
||||
void *ptr = kmap_atomic(page);
|
||||
memset(ptr, 0, PAGE_SIZE);
|
||||
if (coherent_flag != COHERENT)
|
||||
dmac_flush_range(ptr, ptr + PAGE_SIZE);
|
||||
kunmap_atomic(ptr);
|
||||
page++;
|
||||
size -= PAGE_SIZE;
|
||||
}
|
||||
if (coherent_flag != COHERENT)
|
||||
outer_flush_range(base, end);
|
||||
} else {
|
||||
void *ptr = page_address(page);
|
||||
memset(ptr, 0, size);
|
||||
if (coherent_flag != COHERENT) {
|
||||
dmac_flush_range(ptr, ptr + size);
|
||||
outer_flush_range(__pa(ptr), __pa(ptr) + size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a DMA buffer for 'dev' of size 'size' using the
|
||||
* specified gfp mask. Note that 'size' must be page aligned.
|
||||
*/
|
||||
static struct page *__dma_alloc_buffer(struct device *dev, size_t size, gfp_t gfp)
|
||||
static struct page *__dma_alloc_buffer(struct device *dev, size_t size,
|
||||
gfp_t gfp, int coherent_flag)
|
||||
{
|
||||
unsigned long order = get_order(size);
|
||||
struct page *page, *p, *e;
|
||||
|
@ -318,7 +327,7 @@ static struct page *__dma_alloc_buffer(struct device *dev, size_t size, gfp_t gf
|
|||
for (p = page + (size >> PAGE_SHIFT), e = page + (1 << order); p < e; p++)
|
||||
__free_page(p);
|
||||
|
||||
__dma_clear_buffer(page, size);
|
||||
__dma_clear_buffer(page, size, coherent_flag);
|
||||
|
||||
return page;
|
||||
}
|
||||
|
@ -340,7 +349,8 @@ static void __dma_free_buffer(struct page *page, size_t size)
|
|||
|
||||
static void *__alloc_from_contiguous(struct device *dev, size_t size,
|
||||
pgprot_t prot, struct page **ret_page,
|
||||
const void *caller, bool want_vaddr);
|
||||
const void *caller, bool want_vaddr,
|
||||
int coherent_flag);
|
||||
|
||||
static void *__alloc_remap_buffer(struct device *dev, size_t size, gfp_t gfp,
|
||||
pgprot_t prot, struct page **ret_page,
|
||||
|
@ -405,10 +415,13 @@ static int __init atomic_pool_init(void)
|
|||
atomic_pool = gen_pool_create(PAGE_SHIFT, -1);
|
||||
if (!atomic_pool)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* The atomic pool is only used for non-coherent allocations
|
||||
* so we must pass NORMAL for coherent_flag.
|
||||
*/
|
||||
if (dev_get_cma_area(NULL))
|
||||
ptr = __alloc_from_contiguous(NULL, atomic_pool_size, prot,
|
||||
&page, atomic_pool_init, true);
|
||||
&page, atomic_pool_init, true, NORMAL);
|
||||
else
|
||||
ptr = __alloc_remap_buffer(NULL, atomic_pool_size, gfp, prot,
|
||||
&page, atomic_pool_init, true);
|
||||
|
@ -522,7 +535,11 @@ static void *__alloc_remap_buffer(struct device *dev, size_t size, gfp_t gfp,
|
|||
{
|
||||
struct page *page;
|
||||
void *ptr = NULL;
|
||||
page = __dma_alloc_buffer(dev, size, gfp);
|
||||
/*
|
||||
* __alloc_remap_buffer is only called when the device is
|
||||
* non-coherent
|
||||
*/
|
||||
page = __dma_alloc_buffer(dev, size, gfp, NORMAL);
|
||||
if (!page)
|
||||
return NULL;
|
||||
if (!want_vaddr)
|
||||
|
@ -577,7 +594,8 @@ static int __free_from_pool(void *start, size_t size)
|
|||
|
||||
static void *__alloc_from_contiguous(struct device *dev, size_t size,
|
||||
pgprot_t prot, struct page **ret_page,
|
||||
const void *caller, bool want_vaddr)
|
||||
const void *caller, bool want_vaddr,
|
||||
int coherent_flag)
|
||||
{
|
||||
unsigned long order = get_order(size);
|
||||
size_t count = size >> PAGE_SHIFT;
|
||||
|
@ -588,7 +606,7 @@ static void *__alloc_from_contiguous(struct device *dev, size_t size,
|
|||
if (!page)
|
||||
return NULL;
|
||||
|
||||
__dma_clear_buffer(page, size);
|
||||
__dma_clear_buffer(page, size, coherent_flag);
|
||||
|
||||
if (!want_vaddr)
|
||||
goto out;
|
||||
|
@ -638,7 +656,7 @@ static inline pgprot_t __get_dma_pgprot(struct dma_attrs *attrs, pgprot_t prot)
|
|||
#define __get_dma_pgprot(attrs, prot) __pgprot(0)
|
||||
#define __alloc_remap_buffer(dev, size, gfp, prot, ret, c, wv) NULL
|
||||
#define __alloc_from_pool(size, ret_page) NULL
|
||||
#define __alloc_from_contiguous(dev, size, prot, ret, c, wv) NULL
|
||||
#define __alloc_from_contiguous(dev, size, prot, ret, c, wv, coherent_flag) NULL
|
||||
#define __free_from_pool(cpu_addr, size) do { } while (0)
|
||||
#define __free_from_contiguous(dev, page, cpu_addr, size, wv) do { } while (0)
|
||||
#define __dma_free_remap(cpu_addr, size) do { } while (0)
|
||||
|
@ -649,7 +667,8 @@ static void *__alloc_simple_buffer(struct device *dev, size_t size, gfp_t gfp,
|
|||
struct page **ret_page)
|
||||
{
|
||||
struct page *page;
|
||||
page = __dma_alloc_buffer(dev, size, gfp);
|
||||
/* __alloc_simple_buffer is only called when the device is coherent */
|
||||
page = __dma_alloc_buffer(dev, size, gfp, COHERENT);
|
||||
if (!page)
|
||||
return NULL;
|
||||
|
||||
|
@ -679,7 +698,7 @@ static void *cma_allocator_alloc(struct arm_dma_alloc_args *args,
|
|||
{
|
||||
return __alloc_from_contiguous(args->dev, args->size, args->prot,
|
||||
ret_page, args->caller,
|
||||
args->want_vaddr);
|
||||
args->want_vaddr, args->coherent_flag);
|
||||
}
|
||||
|
||||
static void cma_allocator_free(struct arm_dma_free_args *args)
|
||||
|
@ -746,6 +765,7 @@ static void *__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
|
|||
.prot = prot,
|
||||
.caller = caller,
|
||||
.want_vaddr = !dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, attrs),
|
||||
.coherent_flag = is_coherent ? COHERENT : NORMAL,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_DMA_API_DEBUG
|
||||
|
@ -1253,7 +1273,8 @@ static inline void __free_iova(struct dma_iommu_mapping *mapping,
|
|||
static const int iommu_order_array[] = { 9, 8, 4, 0 };
|
||||
|
||||
static struct page **__iommu_alloc_buffer(struct device *dev, size_t size,
|
||||
gfp_t gfp, struct dma_attrs *attrs)
|
||||
gfp_t gfp, struct dma_attrs *attrs,
|
||||
int coherent_flag)
|
||||
{
|
||||
struct page **pages;
|
||||
int count = size >> PAGE_SHIFT;
|
||||
|
@ -1277,7 +1298,7 @@ static struct page **__iommu_alloc_buffer(struct device *dev, size_t size,
|
|||
if (!page)
|
||||
goto error;
|
||||
|
||||
__dma_clear_buffer(page, size);
|
||||
__dma_clear_buffer(page, size, coherent_flag);
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
pages[i] = page + i;
|
||||
|
@ -1327,7 +1348,7 @@ static struct page **__iommu_alloc_buffer(struct device *dev, size_t size,
|
|||
pages[i + j] = pages[i] + j;
|
||||
}
|
||||
|
||||
__dma_clear_buffer(pages[i], PAGE_SIZE << order);
|
||||
__dma_clear_buffer(pages[i], PAGE_SIZE << order, coherent_flag);
|
||||
i += 1 << order;
|
||||
count -= 1 << order;
|
||||
}
|
||||
|
@ -1455,12 +1476,15 @@ static struct page **__iommu_get_pages(void *cpu_addr, struct dma_attrs *attrs)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static void *__iommu_alloc_atomic(struct device *dev, size_t size,
|
||||
dma_addr_t *handle)
|
||||
static void *__iommu_alloc_simple(struct device *dev, size_t size, gfp_t gfp,
|
||||
dma_addr_t *handle, int coherent_flag)
|
||||
{
|
||||
struct page *page;
|
||||
void *addr;
|
||||
|
||||
if (coherent_flag == COHERENT)
|
||||
addr = __alloc_simple_buffer(dev, size, gfp, &page);
|
||||
else
|
||||
addr = __alloc_from_pool(size, &page);
|
||||
if (!addr)
|
||||
return NULL;
|
||||
|
@ -1477,14 +1501,18 @@ err_mapping:
|
|||
}
|
||||
|
||||
static void __iommu_free_atomic(struct device *dev, void *cpu_addr,
|
||||
dma_addr_t handle, size_t size)
|
||||
dma_addr_t handle, size_t size, int coherent_flag)
|
||||
{
|
||||
__iommu_remove_mapping(dev, handle, size);
|
||||
if (coherent_flag == COHERENT)
|
||||
__dma_free_buffer(virt_to_page(cpu_addr), size);
|
||||
else
|
||||
__free_from_pool(cpu_addr, size);
|
||||
}
|
||||
|
||||
static void *arm_iommu_alloc_attrs(struct device *dev, size_t size,
|
||||
dma_addr_t *handle, gfp_t gfp, struct dma_attrs *attrs)
|
||||
static void *__arm_iommu_alloc_attrs(struct device *dev, size_t size,
|
||||
dma_addr_t *handle, gfp_t gfp, struct dma_attrs *attrs,
|
||||
int coherent_flag)
|
||||
{
|
||||
pgprot_t prot = __get_dma_pgprot(attrs, PAGE_KERNEL);
|
||||
struct page **pages;
|
||||
|
@ -1493,8 +1521,9 @@ static void *arm_iommu_alloc_attrs(struct device *dev, size_t size,
|
|||
*handle = DMA_ERROR_CODE;
|
||||
size = PAGE_ALIGN(size);
|
||||
|
||||
if (!gfpflags_allow_blocking(gfp))
|
||||
return __iommu_alloc_atomic(dev, size, handle);
|
||||
if (coherent_flag == COHERENT || !gfpflags_allow_blocking(gfp))
|
||||
return __iommu_alloc_simple(dev, size, gfp, handle,
|
||||
coherent_flag);
|
||||
|
||||
/*
|
||||
* Following is a work-around (a.k.a. hack) to prevent pages
|
||||
|
@ -1505,7 +1534,7 @@ static void *arm_iommu_alloc_attrs(struct device *dev, size_t size,
|
|||
*/
|
||||
gfp &= ~(__GFP_COMP);
|
||||
|
||||
pages = __iommu_alloc_buffer(dev, size, gfp, attrs);
|
||||
pages = __iommu_alloc_buffer(dev, size, gfp, attrs, coherent_flag);
|
||||
if (!pages)
|
||||
return NULL;
|
||||
|
||||
|
@ -1530,7 +1559,19 @@ err_buffer:
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static int arm_iommu_mmap_attrs(struct device *dev, struct vm_area_struct *vma,
|
||||
static void *arm_iommu_alloc_attrs(struct device *dev, size_t size,
|
||||
dma_addr_t *handle, gfp_t gfp, struct dma_attrs *attrs)
|
||||
{
|
||||
return __arm_iommu_alloc_attrs(dev, size, handle, gfp, attrs, NORMAL);
|
||||
}
|
||||
|
||||
static void *arm_coherent_iommu_alloc_attrs(struct device *dev, size_t size,
|
||||
dma_addr_t *handle, gfp_t gfp, struct dma_attrs *attrs)
|
||||
{
|
||||
return __arm_iommu_alloc_attrs(dev, size, handle, gfp, attrs, COHERENT);
|
||||
}
|
||||
|
||||
static int __arm_iommu_mmap_attrs(struct device *dev, struct vm_area_struct *vma,
|
||||
void *cpu_addr, dma_addr_t dma_addr, size_t size,
|
||||
struct dma_attrs *attrs)
|
||||
{
|
||||
|
@ -1540,8 +1581,6 @@ static int arm_iommu_mmap_attrs(struct device *dev, struct vm_area_struct *vma,
|
|||
unsigned long nr_pages = PAGE_ALIGN(size) >> PAGE_SHIFT;
|
||||
unsigned long off = vma->vm_pgoff;
|
||||
|
||||
vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot);
|
||||
|
||||
if (!pages)
|
||||
return -ENXIO;
|
||||
|
||||
|
@ -1562,19 +1601,34 @@ static int arm_iommu_mmap_attrs(struct device *dev, struct vm_area_struct *vma,
|
|||
|
||||
return 0;
|
||||
}
|
||||
static int arm_iommu_mmap_attrs(struct device *dev,
|
||||
struct vm_area_struct *vma, void *cpu_addr,
|
||||
dma_addr_t dma_addr, size_t size, struct dma_attrs *attrs)
|
||||
{
|
||||
vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot);
|
||||
|
||||
return __arm_iommu_mmap_attrs(dev, vma, cpu_addr, dma_addr, size, attrs);
|
||||
}
|
||||
|
||||
static int arm_coherent_iommu_mmap_attrs(struct device *dev,
|
||||
struct vm_area_struct *vma, void *cpu_addr,
|
||||
dma_addr_t dma_addr, size_t size, struct dma_attrs *attrs)
|
||||
{
|
||||
return __arm_iommu_mmap_attrs(dev, vma, cpu_addr, dma_addr, size, attrs);
|
||||
}
|
||||
|
||||
/*
|
||||
* free a page as defined by the above mapping.
|
||||
* Must not be called with IRQs disabled.
|
||||
*/
|
||||
void arm_iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr,
|
||||
dma_addr_t handle, struct dma_attrs *attrs)
|
||||
void __arm_iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr,
|
||||
dma_addr_t handle, struct dma_attrs *attrs, int coherent_flag)
|
||||
{
|
||||
struct page **pages;
|
||||
size = PAGE_ALIGN(size);
|
||||
|
||||
if (__in_atomic_pool(cpu_addr, size)) {
|
||||
__iommu_free_atomic(dev, cpu_addr, handle, size);
|
||||
if (coherent_flag == COHERENT || __in_atomic_pool(cpu_addr, size)) {
|
||||
__iommu_free_atomic(dev, cpu_addr, handle, size, coherent_flag);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1593,6 +1647,18 @@ void arm_iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr,
|
|||
__iommu_free_buffer(dev, pages, size, attrs);
|
||||
}
|
||||
|
||||
void arm_iommu_free_attrs(struct device *dev, size_t size,
|
||||
void *cpu_addr, dma_addr_t handle, struct dma_attrs *attrs)
|
||||
{
|
||||
__arm_iommu_free_attrs(dev, size, cpu_addr, handle, attrs, NORMAL);
|
||||
}
|
||||
|
||||
void arm_coherent_iommu_free_attrs(struct device *dev, size_t size,
|
||||
void *cpu_addr, dma_addr_t handle, struct dma_attrs *attrs)
|
||||
{
|
||||
__arm_iommu_free_attrs(dev, size, cpu_addr, handle, attrs, COHERENT);
|
||||
}
|
||||
|
||||
static int arm_iommu_get_sgtable(struct device *dev, struct sg_table *sgt,
|
||||
void *cpu_addr, dma_addr_t dma_addr,
|
||||
size_t size, struct dma_attrs *attrs)
|
||||
|
@ -1997,9 +2063,9 @@ struct dma_map_ops iommu_ops = {
|
|||
};
|
||||
|
||||
struct dma_map_ops iommu_coherent_ops = {
|
||||
.alloc = arm_iommu_alloc_attrs,
|
||||
.free = arm_iommu_free_attrs,
|
||||
.mmap = arm_iommu_mmap_attrs,
|
||||
.alloc = arm_coherent_iommu_alloc_attrs,
|
||||
.free = arm_coherent_iommu_free_attrs,
|
||||
.mmap = arm_coherent_iommu_mmap_attrs,
|
||||
.get_sgtable = arm_iommu_get_sgtable,
|
||||
|
||||
.map_page = arm_coherent_iommu_map_page,
|
||||
|
|
|
@ -362,6 +362,39 @@ __ca15_errata:
|
|||
#endif
|
||||
b __errata_finish
|
||||
|
||||
__ca12_errata:
|
||||
#ifdef CONFIG_ARM_ERRATA_818325_852422
|
||||
mrc p15, 0, r10, c15, c0, 1 @ read diagnostic register
|
||||
orr r10, r10, #1 << 12 @ set bit #12
|
||||
mcr p15, 0, r10, c15, c0, 1 @ write diagnostic register
|
||||
#endif
|
||||
#ifdef CONFIG_ARM_ERRATA_821420
|
||||
mrc p15, 0, r10, c15, c0, 2 @ read internal feature reg
|
||||
orr r10, r10, #1 << 1 @ set bit #1
|
||||
mcr p15, 0, r10, c15, c0, 2 @ write internal feature reg
|
||||
#endif
|
||||
#ifdef CONFIG_ARM_ERRATA_825619
|
||||
mrc p15, 0, r10, c15, c0, 1 @ read diagnostic register
|
||||
orr r10, r10, #1 << 24 @ set bit #24
|
||||
mcr p15, 0, r10, c15, c0, 1 @ write diagnostic register
|
||||
#endif
|
||||
b __errata_finish
|
||||
|
||||
__ca17_errata:
|
||||
#ifdef CONFIG_ARM_ERRATA_852421
|
||||
cmp r6, #0x12 @ only present up to r1p2
|
||||
mrcle p15, 0, r10, c15, c0, 1 @ read diagnostic register
|
||||
orrle r10, r10, #1 << 24 @ set bit #24
|
||||
mcrle p15, 0, r10, c15, c0, 1 @ write diagnostic register
|
||||
#endif
|
||||
#ifdef CONFIG_ARM_ERRATA_852423
|
||||
cmp r6, #0x12 @ only present up to r1p2
|
||||
mrcle p15, 0, r10, c15, c0, 1 @ read diagnostic register
|
||||
orrle r10, r10, #1 << 12 @ set bit #12
|
||||
mcrle p15, 0, r10, c15, c0, 1 @ write diagnostic register
|
||||
#endif
|
||||
b __errata_finish
|
||||
|
||||
__v7_pj4b_setup:
|
||||
#ifdef CONFIG_CPU_PJ4B
|
||||
|
||||
|
@ -443,6 +476,16 @@ __v7_setup_cont:
|
|||
teq r0, r10
|
||||
beq __ca9_errata
|
||||
|
||||
/* Cortex-A12 Errata */
|
||||
ldr r10, =0x00000c0d @ Cortex-A12 primary part number
|
||||
teq r0, r10
|
||||
beq __ca12_errata
|
||||
|
||||
/* Cortex-A17 Errata */
|
||||
ldr r10, =0x00000c0e @ Cortex-A17 primary part number
|
||||
teq r0, r10
|
||||
beq __ca17_errata
|
||||
|
||||
/* Cortex-A15 Errata */
|
||||
ldr r10, =0x00000c0f @ Cortex-A15 primary part number
|
||||
teq r0, r10
|
||||
|
|
Loading…
Reference in New Issue