Commit 12679a2d authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.linaro.org/people/rmk/linux-arm

Pull more ARM updates from Russell King.

This got a fair number of conflicts with the <asm/system.h> split, but
also with some other sparse-irq and header file include cleanups.  They
all looked pretty trivial, though.

* 'for-linus' of git://git.linaro.org/people/rmk/linux-arm: (59 commits)
  ARM: fix Kconfig warning for HAVE_BPF_JIT
  ARM: 7361/1: provide XIP_VIRT_ADDR for no-MMU builds
  ARM: 7349/1: integrator: convert to sparse irqs
  ARM: 7259/3: net: JIT compiler for packet filters
  ARM: 7334/1: add jump label support
  ARM: 7333/2: jump label: detect %c support for ARM
  ARM: 7338/1: add support for early console output via semihosting
  ARM: use set_current_blocked() and block_sigmask()
  ARM: exec: remove redundant set_fs(USER_DS)
  ARM: 7332/1: extract out code patch function from kprobes
  ARM: 7331/1: extract out insn generation code from ftrace
  ARM: 7330/1: ftrace: use canonical Thumb-2 wide instruction format
  ARM: 7351/1: ftrace: remove useless memory checks
  ARM: 7316/1: kexec: EOI active and mask all interrupts in kexec crash path
  ARM: Versatile Express: add NO_IOPORT
  ARM: get rid of asm/irq.h in asm/prom.h
  ARM: 7319/1: Print debug info for SIGBUS in user faults
  ARM: 7318/1: gic: refactor irq_start assignment
  ARM: 7317/1: irq: avoid NULL check in for_each_irq_desc loop
  ARM: 7315/1: perf: add support for the Cortex-A7 PMU
  ...
parents 1c036588 b0df8986
......@@ -9,6 +9,7 @@ config ARM
select SYS_SUPPORTS_APM_EMULATION
select GENERIC_ATOMIC64 if (CPU_V6 || !CPU_32v6K || !AEABI)
select HAVE_OPROFILE if (HAVE_PERF_EVENTS)
select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL
select HAVE_ARCH_KGDB
select HAVE_KPROBES if !XIP_KERNEL
select HAVE_KRETPROBES if (HAVE_KPROBES)
......@@ -21,6 +22,7 @@ config ARM
select HAVE_KERNEL_GZIP
select HAVE_KERNEL_LZO
select HAVE_KERNEL_LZMA
select HAVE_KERNEL_XZ
select HAVE_IRQ_WORK
select HAVE_PERF_EVENTS
select PERF_USE_VMALLOC
......@@ -28,10 +30,10 @@ config ARM
select HAVE_HW_BREAKPOINT if (PERF_EVENTS && (CPU_V6 || CPU_V6K || CPU_V7))
select HAVE_C_RECORDMCOUNT
select HAVE_GENERIC_HARDIRQS
select HAVE_SPARSE_IRQ
select GENERIC_IRQ_SHOW
select CPU_PM if (SUSPEND || CPU_IDLE)
select GENERIC_PCI_IOMAP
select HAVE_BPF_JIT if NET
help
The ARM series is a line of low-power-consumption RISC chip designs
licensed by ARM Ltd and targeted at embedded applications and
......@@ -52,9 +54,6 @@ config MIGHT_HAVE_PCI
config SYS_SUPPORTS_APM_EMULATION
bool
config HAVE_SCHED_CLOCK
bool
config GENERIC_GPIO
bool
......@@ -269,6 +268,7 @@ config ARCH_INTEGRATOR
select PLAT_VERSATILE
select PLAT_VERSATILE_FPGA_IRQ
select NEED_MACH_MEMORY_H
select SPARSE_IRQ
help
Support for ARM's Integrator platform.
......@@ -315,6 +315,7 @@ config ARCH_VEXPRESS
select HAVE_CLK
select HAVE_PATA_PLATFORM
select ICST
select NO_IOPORT
select PLAT_VERSATILE
select PLAT_VERSATILE_CLCD
help
......@@ -354,6 +355,7 @@ config ARCH_HIGHBANK
select GENERIC_CLOCKEVENTS
select HAVE_ARM_SCU
select HAVE_SMP
select SPARSE_IRQ
select USE_OF
help
Support for the Calxeda Highbank SoC based boards.
......@@ -442,7 +444,6 @@ config ARCH_MXC
select CLKDEV_LOOKUP
select CLKSRC_MMIO
select GENERIC_IRQ_CHIP
select HAVE_SCHED_CLOCK
select MULTI_IRQ_HANDLER
help
Support for Freescale MXC/iMX-based family of processors
......@@ -537,7 +538,6 @@ config ARCH_IXP4XX
select CPU_XSCALE
select GENERIC_GPIO
select GENERIC_CLOCKEVENTS
select HAVE_SCHED_CLOCK
select MIGHT_HAVE_PCI
select DMABOUNCE if PCI
help
......@@ -608,7 +608,6 @@ config ARCH_MMP
select CLKDEV_LOOKUP
select GENERIC_CLOCKEVENTS
select GPIO_PXA
select HAVE_SCHED_CLOCK
select TICK_ONESHOT
select PLAT_PXA
select SPARSE_IRQ
......@@ -649,7 +648,6 @@ config ARCH_TEGRA
select GENERIC_CLOCKEVENTS
select GENERIC_GPIO
select HAVE_CLK
select HAVE_SCHED_CLOCK
select HAVE_SMP
select MIGHT_HAVE_CACHE_L2X0
select ARCH_HAS_CPUFREQ
......@@ -666,7 +664,6 @@ config ARCH_PICOXCELL
select DW_APB_TIMER
select GENERIC_CLOCKEVENTS
select GENERIC_GPIO
select HAVE_SCHED_CLOCK
select HAVE_TCM
select NO_IOPORT
select SPARSE_IRQ
......@@ -694,7 +691,6 @@ config ARCH_PXA
select ARCH_REQUIRE_GPIOLIB
select GENERIC_CLOCKEVENTS
select GPIO_PXA
select HAVE_SCHED_CLOCK
select TICK_ONESHOT
select PLAT_PXA
select SPARSE_IRQ
......@@ -761,7 +757,6 @@ config ARCH_SA1100
select CPU_FREQ
select GENERIC_CLOCKEVENTS
select CLKDEV_LOOKUP
select HAVE_SCHED_CLOCK
select TICK_ONESHOT
select ARCH_REQUIRE_GPIOLIB
select HAVE_IDE
......@@ -818,7 +813,6 @@ config ARCH_S5P64X0
select CLKSRC_MMIO
select HAVE_S3C2410_WATCHDOG if WATCHDOG
select GENERIC_CLOCKEVENTS
select HAVE_SCHED_CLOCK
select HAVE_S3C2410_I2C if I2C
select HAVE_S3C_RTC if RTC_CLASS
help
......@@ -849,7 +843,6 @@ config ARCH_S5PV210
select CLKSRC_MMIO
select ARCH_HAS_CPUFREQ
select GENERIC_CLOCKEVENTS
select HAVE_SCHED_CLOCK
select HAVE_S3C2410_I2C if I2C
select HAVE_S3C_RTC if RTC_CLASS
select HAVE_S3C2410_WATCHDOG if WATCHDOG
......@@ -892,7 +885,6 @@ config ARCH_U300
depends on MMU
select CLKSRC_MMIO
select CPU_ARM926T
select HAVE_SCHED_CLOCK
select HAVE_TCM
select ARM_AMBA
select ARM_PATCH_PHYS_VIRT
......@@ -951,7 +943,6 @@ config ARCH_OMAP
select ARCH_HAS_CPUFREQ
select CLKSRC_MMIO
select GENERIC_CLOCKEVENTS
select HAVE_SCHED_CLOCK
select ARCH_HAS_HOLES_MEMORYMODEL
help
Support for TI's OMAP platform (OMAP1/2/3/4).
......@@ -1115,13 +1106,11 @@ config ARCH_ACORN
config PLAT_IOP
bool
select GENERIC_CLOCKEVENTS
select HAVE_SCHED_CLOCK
config PLAT_ORION
bool
select CLKSRC_MMIO
select GENERIC_IRQ_CHIP
select HAVE_SCHED_CLOCK
config PLAT_PXA
bool
......
......@@ -292,6 +292,22 @@ choice
Note that the system will appear to hang during boot if there
is nothing connected to read from the DCC.
config DEBUG_SEMIHOSTING
bool "Kernel low-level debug output via semihosting I"
help
Semihosting enables code running on an ARM target to use
the I/O facilities on a host debugger/emulator through a
simple SVC calls. The host debugger or emulator must have
semihosting enabled for the special svc call to be trapped
otherwise the kernel will crash.
This is known to work with OpenOCD, as wellas
ARM's Fast Models, or any other controlling environment
that implements semihosting.
For more details about semihosting, please see
chapter 8 of DUI0203I_rvct_developer_guide.pdf from ARM Ltd.
endchoice
config EARLY_PRINTK
......
......@@ -253,6 +253,7 @@ core-$(CONFIG_VFP) += arch/arm/vfp/
# If we have a machine-specific directory, then include it in the build.
core-y += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/
core-y += arch/arm/net/
core-y += $(machdirs) $(platdirs)
drivers-$(CONFIG_OPROFILE) += arch/arm/oprofile/
......
ashldi3.S
font.c
lib1funcs.S
piggy.gzip
piggy.lzo
piggy.lzma
piggy.xzkern
vmlinux
vmlinux.lds
......
......@@ -92,6 +92,7 @@ SEDFLAGS = s/TEXT_START/$(ZTEXTADDR)/;s/BSS_START/$(ZBSSADDR)/
suffix_$(CONFIG_KERNEL_GZIP) = gzip
suffix_$(CONFIG_KERNEL_LZO) = lzo
suffix_$(CONFIG_KERNEL_LZMA) = lzma
suffix_$(CONFIG_KERNEL_XZ) = xzkern
# Borrowed libfdt files for the ATAG compatibility mode
......@@ -112,10 +113,12 @@ endif
targets := vmlinux vmlinux.lds \
piggy.$(suffix_y) piggy.$(suffix_y).o \
lib1funcs.o lib1funcs.S font.o font.c head.o misc.o $(OBJS)
lib1funcs.o lib1funcs.S ashldi3.o ashldi3.S \
font.o font.c head.o misc.o $(OBJS)
# Make sure files are removed during clean
extra-y += piggy.gzip piggy.lzo piggy.lzma lib1funcs.S $(libfdt) $(libfdt_hdrs)
extra-y += piggy.gzip piggy.lzo piggy.lzma piggy.xzkern \
lib1funcs.S ashldi3.S $(libfdt) $(libfdt_hdrs)
ifeq ($(CONFIG_FUNCTION_TRACER),y)
ORIG_CFLAGS := $(KBUILD_CFLAGS)
......@@ -151,6 +154,12 @@ lib1funcs = $(obj)/lib1funcs.o
$(obj)/lib1funcs.S: $(srctree)/arch/$(SRCARCH)/lib/lib1funcs.S
$(call cmd,shipped)
# For __aeabi_llsl
ashldi3 = $(obj)/ashldi3.o
$(obj)/ashldi3.S: $(srctree)/arch/$(SRCARCH)/lib/ashldi3.S
$(call cmd,shipped)
# We need to prevent any GOTOFF relocs being used with references
# to symbols in the .bss section since we cannot relocate them
# independently from the rest at run time. This can be achieved by
......@@ -172,7 +181,7 @@ if [ $(words $(ZRELADDR)) -gt 1 -a "$(CONFIG_AUTO_ZRELADDR)" = "" ]; then \
fi
$(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/$(HEAD) $(obj)/piggy.$(suffix_y).o \
$(addprefix $(obj)/, $(OBJS)) $(lib1funcs) FORCE
$(addprefix $(obj)/, $(OBJS)) $(lib1funcs) $(ashldi3) FORCE
@$(check_for_multiple_zreladdr)
$(call if_changed,ld)
@$(check_for_bad_syms)
......
......@@ -44,6 +44,12 @@ extern void error(char *);
#include "../../../../lib/decompress_unlzma.c"
#endif
#ifdef CONFIG_KERNEL_XZ
#define memmove memmove
#define memcpy memcpy
#include "../../../../lib/decompress_unxz.c"
#endif
int do_decompress(u8 *input, int len, u8 *output, void (*error)(char *x))
{
return decompress(input, len, NULL, NULL, output, NULL, error);
......
.section .piggydata,#alloc
.globl input_data
input_data:
.incbin "arch/arm/boot/compressed/piggy.xzkern"
.globl input_data_end
input_data_end:
......@@ -686,13 +686,12 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
* For primary GICs, skip over SGIs.
* For secondary GICs, skip over PPIs, too.
*/
hwirq_base = 32;
if (gic_nr == 0) {
if ((irq_start & 31) > 0) {
if (gic_nr == 0 && (irq_start & 31) > 0) {
hwirq_base = 16;
if (irq_start != -1)
irq_start = (irq_start & ~31) + 16;
}
} else {
hwirq_base = 32;
}
/*
......
......@@ -57,18 +57,24 @@ CONFIG_NETDEVICES=y
CONFIG_NET_ETHERNET=y
CONFIG_NET_PCI=y
CONFIG_E100=y
CONFIG_SMC91X=y
# CONFIG_KEYBOARD_ATKBD is not set
# CONFIG_SERIO_SERPORT is not set
CONFIG_SERIAL_AMBA_PL010=y
CONFIG_SERIAL_AMBA_PL010_CONSOLE=y
CONFIG_FB=y
CONFIG_FB_MODE_HELPERS=y
CONFIG_FB_ARMCLCD=y
CONFIG_FB_MATROX=y
CONFIG_FB_MATROX_MILLENIUM=y
CONFIG_FB_MATROX_MYSTIQUE=y
# CONFIG_VGA_CONSOLE is not set
CONFIG_MMC=y
CONFIG_MMC_ARMMMCI=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_PL030=y
CONFIG_EXT2_FS=y
CONFIG_VFAT_FS=y
CONFIG_TMPFS=y
CONFIG_JFFS2_FS=y
CONFIG_CRAMFS=y
......@@ -78,5 +84,7 @@ CONFIG_ROOT_NFS=y
CONFIG_NFSD=y
CONFIG_NFSD_V3=y
CONFIG_PARTITION_ADVANCED=y
CONFIG_NLS_CODEPAGE_437=y
CONFIG_NLS_ISO8859_1=y
CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_KERNEL=y
......@@ -130,8 +130,4 @@ struct mm_struct;
extern unsigned long arch_randomize_brk(struct mm_struct *mm);
#define arch_randomize_brk arch_randomize_brk
extern int vectors_user_mapping(void);
#define arch_setup_additional_pages(bprm, uses_interp) vectors_user_mapping()
#define ARCH_HAS_SETUP_ADDITIONAL_PAGES
#endif
......@@ -103,11 +103,11 @@
#define L2X0_ADDR_FILTER_EN 1
#ifndef __ASSEMBLY__
extern void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask);
extern void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask);
#if defined(CONFIG_CACHE_L2X0) && defined(CONFIG_OF)
extern int l2x0_of_init(__u32 aux_val, __u32 aux_mask);
extern int l2x0_of_init(u32 aux_val, u32 aux_mask);
#else
static inline int l2x0_of_init(__u32 aux_val, __u32 aux_mask)
static inline int l2x0_of_init(u32 aux_val, u32 aux_mask)
{
return -ENODEV;
}
......
......@@ -9,6 +9,9 @@
#ifndef __ASM_HARDWARE_IT8152_H
#define __ASM_HARDWARE_IT8152_H
#include <mach/irqs.h>
extern void __iomem *it8152_base_address;
#define IT8152_IO_BASE (it8152_base_address + 0x03e00000)
......
#ifndef __ASM_ARM_IRQ_H
#define __ASM_ARM_IRQ_H
#define NR_IRQS_LEGACY 16
#ifndef CONFIG_SPARSE_IRQ
#include <mach/irqs.h>
#else
#define NR_IRQS NR_IRQS_LEGACY
#endif
#ifndef irq_canonicalize
#define irq_canonicalize(i) (i)
#endif
#define NR_IRQS_LEGACY 16
/*
* Use this value to indicate lack of interrupt
* capability
......
#ifndef _ASM_ARM_JUMP_LABEL_H
#define _ASM_ARM_JUMP_LABEL_H
#ifdef __KERNEL__
#include <linux/types.h>
#include <asm/system.h>
#define JUMP_LABEL_NOP_SIZE 4
#ifdef CONFIG_THUMB2_KERNEL
#define JUMP_LABEL_NOP "nop.w"
#else
#define JUMP_LABEL_NOP "nop"
#endif
static __always_inline bool arch_static_branch(struct jump_label_key *key)
{
asm goto("1:\n\t"
JUMP_LABEL_NOP "\n\t"
".pushsection __jump_table, \"aw\"\n\t"
".word 1b, %l[l_yes], %c0\n\t"
".popsection\n\t"
: : "i" (key) : : l_yes);
return false;
l_yes:
return true;
}
#endif /* __KERNEL__ */
typedef u32 jump_label_t;
struct jump_entry {
jump_label_t code;
jump_label_t target;
jump_label_t key;
};
#endif
......@@ -5,7 +5,9 @@
#define _ASM_MC146818RTC_H
#include <linux/io.h>
#include <mach/irqs.h>
#include <linux/kernel.h>
#define RTC_IRQ BUILD_BUG_ON(1)
#ifndef RTC_PORT
#define RTC_PORT(x) (0x70 + (x))
......
......@@ -116,6 +116,8 @@
#define MODULES_END (END_MEM)
#define MODULES_VADDR (PHYS_OFFSET)
#define XIP_VIRT_ADDR(physaddr) (physaddr)
#endif /* !CONFIG_MMU */
/*
......
......@@ -18,6 +18,7 @@
#include <asm/cacheflush.h>
#include <asm/cachetype.h>
#include <asm/proc-fns.h>
#include <asm-generic/mm_hooks.h>
void __check_kvm_seq(struct mm_struct *mm);
......@@ -133,32 +134,4 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next,
#define deactivate_mm(tsk,mm) do { } while (0)
#define activate_mm(prev,next) switch_mm(prev, next, NULL)
/*
* We are inserting a "fake" vma for the user-accessible vector page so
* gdb and friends can get to it through ptrace and /proc/<pid>/mem.
* But we also want to remove it before the generic code gets to see it
* during process exit or the unmapping of it would cause total havoc.
* (the macro is used as remove_vma() is static to mm/mmap.c)
*/
#define arch_exit_mmap(mm) \
do { \
struct vm_area_struct *high_vma = find_vma(mm, 0xffff0000); \
if (high_vma) { \
BUG_ON(high_vma->vm_next); /* it should be last */ \
if (high_vma->vm_prev) \
high_vma->vm_prev->vm_next = NULL; \
else \
mm->mmap = NULL; \
rb_erase(&high_vma->vm_rb, &mm->mm_rb); \
mm->mmap_cache = NULL; \
mm->map_count--; \
remove_vma(high_vma); \
} \
} while (0)
static inline void arch_dup_mmap(struct mm_struct *oldmm,
struct mm_struct *mm)
{
}
#endif
......@@ -17,4 +17,63 @@ extern asmlinkage unsigned int arm_check_condition(u32 opcode, u32 psr);
#define ARM_OPCODE_CONDTEST_PASS 1
#define ARM_OPCODE_CONDTEST_UNCOND 2
/*
* Opcode byteswap helpers
*
* These macros help with converting instructions between a canonical integer
* format and in-memory representation, in an endianness-agnostic manner.
*
* __mem_to_opcode_*() convert from in-memory representation to canonical form.
* __opcode_to_mem_*() convert from canonical form to in-memory representation.
*
*
* Canonical instruction representation:
*
* ARM: 0xKKLLMMNN
* Thumb 16-bit: 0x0000KKLL, where KK < 0xE8
* Thumb 32-bit: 0xKKLLMMNN, where KK >= 0xE8
*
* There is no way to distinguish an ARM instruction in canonical representation
* from a Thumb instruction (just as these cannot be distinguished in memory).
* Where this distinction is important, it needs to be tracked separately.
*
* Note that values in the range 0x0000E800..0xE7FFFFFF intentionally do not
* represent any valid Thumb-2 instruction. For this range,
* __opcode_is_thumb32() and __opcode_is_thumb16() will both be false.
*/
#ifndef __ASSEMBLY__
#include <linux/types.h>
#include <linux/swab.h>
#ifdef CONFIG_CPU_ENDIAN_BE8
#define __opcode_to_mem_arm(x) swab32(x)
#define __opcode_to_mem_thumb16(x) swab16(x)
#define __opcode_to_mem_thumb32(x) swahb32(x)
#else
#define __opcode_to_mem_arm(x) ((u32)(x))
#define __opcode_to_mem_thumb16(x) ((u16)(x))
#define __opcode_to_mem_thumb32(x) swahw32(x)
#endif
#define __mem_to_opcode_arm(x) __opcode_to_mem_arm(x)
#define __mem_to_opcode_thumb16(x) __opcode_to_mem_thumb16(x)
#define __mem_to_opcode_thumb32(x) __opcode_to_mem_thumb32(x)
/* Operations specific to Thumb opcodes */
/* Instruction size checks: */
#define __opcode_is_thumb32(x) ((u32)(x) >= 0xE8000000UL)
#define __opcode_is_thumb16(x) ((u32)(x) < 0xE800UL)
/* Operations to construct or split 32-bit Thumb instructions: */
#define __opcode_thumb32_first(x) ((u16)((x) >> 16))
#define __opcode_thumb32_second(x) ((u16)(x))
#define __opcode_thumb32_compose(first, second) \
(((u32)(u16)(first) << 16) | (u32)(u16)(second))
#endif /* __ASSEMBLY__ */
#endif /* __ASM_ARM_OPCODES_H */
......@@ -151,6 +151,8 @@ extern void __cpu_copy_user_highpage(struct page *to, struct page *from,
#define clear_page(page) memset((void *)(page), 0, PAGE_SIZE)
extern void copy_page(void *to, const void *from);
#define __HAVE_ARCH_GATE_AREA 1
#ifdef CONFIG_ARM_LPAE
#include <asm/pgtable-3level-types.h>
#else
......
......@@ -22,6 +22,7 @@ enum arm_perf_pmu_ids {
ARM_PERF_PMU_ID_CA9,
ARM_PERF_PMU_ID_CA5,
ARM_PERF_PMU_ID_CA15,
ARM_PERF_PMU_ID_CA7,
ARM_NUM_PMU_IDS,
};
......
......@@ -55,7 +55,6 @@ struct thread_struct {
#define start_thread(regs,pc,sp) \
({ \
unsigned long *stack = (unsigned long *)sp; \
set_fs(USER_DS); \
memset(regs->uregs, 0, sizeof(regs->uregs)); \
if (current->personality & ADDR_LIMIT_32BIT) \
regs->ARM_cpsr = USR_MODE; \
......
......@@ -13,8 +13,6 @@
#ifdef CONFIG_OF
#include <asm/irq.h>
extern struct machine_desc *setup_machine_fdt(unsigned int dt_phys);
extern void arm_dt_memblock_reserve(void);
......
......@@ -318,6 +318,21 @@ extern struct cpu_tlb_fns cpu_tlb;
#define tlb_flag(f) ((always_tlb_flags & (f)) || (__tlb_flag & possible_tlb_flags & (f)))
#define __tlb_op(f, insnarg, arg) \
do { \
if (always_tlb_flags & (f)) \
asm("mcr " insnarg \
: : "r" (arg) : "cc"); \
else if (possible_tlb_flags & (f)) \
asm("tst %1, %2\n\t" \
"mcrne " insnarg \
: : "r" (arg), "r" (__tlb_flag), "Ir" (f) \
: "cc"); \
} while (0)
#define tlb_op(f, regs, arg) __tlb_op(f, "p15, 0, %0, " regs, arg)
#define tlb_l2_op(f, regs, arg) __tlb_op(f, "p15, 1, %0, " regs, arg)
static inline void local_flush_tlb_all(void)
{
const int zero = 0;
......@@ -326,16 +341,11 @@ static inline void local_flush_tlb_all(void)
if (tlb_flag(TLB_WB))
dsb();
if (tlb_flag(TLB_V3_FULL))
asm("mcr p15, 0, %0, c6, c0, 0" : : "r" (zero) : "cc");
if (tlb_flag(TLB_V4_U_FULL | TLB_V6_U_FULL))
asm("mcr p15, 0, %0, c8, c7, 0" : : "r" (zero) : "cc");
if (tlb_flag(TLB_V4_D_FULL | TLB_V6_D_FULL))
asm("mcr p15, 0, %0, c8, c6, 0" : : "r" (zero) : "cc");
if (tlb_flag(TLB_V4_I_FULL | TLB_V6_I_FULL))
asm("mcr p15, 0, %0, c8, c5, 0" : : "r" (zero) : "cc");
if (tlb_flag(TLB_V7_UIS_FULL))
asm("mcr p15, 0, %0, c8, c3, 0" : : "r" (zero) : "cc");
tlb_op(TLB_V3_FULL, "c6, c0, 0", zero);
tlb_op(TLB_V4_U_FULL | TLB_V6_U_FULL, "c8, c7, 0", zero);
tlb_op(TLB_V4_D_FULL | TLB_V6_D_FULL, "c8, c6, 0", zero);
tlb_op(TLB_V4_I_FULL | TLB_V6_I_FULL, "c8, c5, 0", zero);
tlb_op(TLB_V7_UIS_FULL, "c8, c3, 0", zero);
if (tlb_flag(TLB_BARRIER)) {
dsb();
......@@ -352,29 +362,23 @@ static inline void local_flush_tlb_mm(struct mm_struct *mm)
if (tlb_flag(TLB_WB))
dsb();
if (possible_tlb_flags & (TLB_V3_FULL|TLB_V4_U_FULL|TLB_V4_D_FULL|TLB_V4_I_FULL)) {
if (cpumask_test_cpu(get_cpu(), mm_cpumask(mm))) {
if (tlb_flag(TLB_V3_FULL))
asm("mcr p15, 0, %0, c6, c0, 0" : : "r" (zero) : "cc");
if (tlb_flag(TLB_V4_U_FULL))
asm("mcr p15, 0, %0, c8, c7, 0" : : "r" (zero) : "cc");
if (tlb_flag(TLB_V4_D_FULL))
asm("mcr p15, 0, %0, c8, c6, 0" : : "r" (zero) : "cc");
if (tlb_flag(TLB_V4_I_FULL))
asm("mcr p15, 0, %0, c8, c5, 0" : : "r" (zero) : "cc");
tlb_op(TLB_V3_FULL, "c6, c0, 0", zero);
tlb_op(TLB_V4_U_FULL, "c8, c7, 0", zero);
tlb_op(TLB_V4_D_FULL, "c8, c6, 0", zero);
tlb_op(TLB_V4_I_FULL, "c8, c5, 0", zero);
}
put_cpu();
}
if (tlb_flag(TLB_V6_U_ASID))
asm("mcr p15, 0, %0, c8, c7, 2" : : "r" (asid) : "cc");
if (tlb_flag(TLB_V6_D_ASID))
asm("mcr p15, 0, %0, c8, c6, 2" : : "r" (asid) : "cc");
if (tlb_flag(TLB_V6_I_ASID))
asm("mcr p15, 0, %0, c8, c5, 2" : : "r" (asid) : "cc");
if (tlb_flag(TLB_V7_UIS_ASID))
tlb_op(TLB_V6_U_ASID, "c8, c7, 2", asid);
tlb_op(TLB_V6_D_ASID, "c8, c6, 2", asid);
tlb_op(TLB_V6_I_ASID, "c8, c5, 2", asid);
#ifdef CONFIG_ARM_ERRATA_720789
asm("mcr p15, 0, %0, c8, c3, 0" : : "r" (zero) : "cc");
tlb_op(TLB_V7_UIS_ASID, "c8, c3, 0", zero);
#else
asm("mcr p15, 0, %0, c8, c3, 2" : : "r" (asid) : "cc");
tlb_op(TLB_V7_UIS_ASID, "c8, c3, 2", asid);
#endif
if (tlb_flag(TLB_BARRIER))
......@@ -392,30 +396,23 @@ local_flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
if (tlb_flag(TLB_WB))
dsb();
if (cpumask_test_cpu(smp_processor_id(), mm_cpumask(vma->vm_mm))) {
if (tlb_flag(TLB_V3_PAGE))
asm("mcr p15, 0, %0, c6, c0, 0" : : "r" (uaddr) : "cc");
if (tlb_flag(TLB_V4_U_PAGE))
asm("mcr p15, 0, %0, c8, c7, 1" : : "r" (uaddr) : "cc");
if (tlb_flag(TLB_V4_D_PAGE))
asm("mcr p15, 0, %0, c8, c6, 1" : : "r" (uaddr) : "cc");
if (tlb_flag(TLB_V4_I_PAGE))
asm("mcr p15, 0, %0, c8, c5, 1" : : "r" (uaddr) : "cc");
if (possible_tlb_flags & (TLB_V3_PAGE|TLB_V4_U_PAGE|TLB_V4_D_PAGE|TLB_V4_I_PAGE|TLB_V4_I_FULL) &&
cpumask_test_cpu(smp_processor_id(), mm_cpumask(vma->vm_mm))) {
tlb_op(TLB_V3_PAGE, "c6, c0, 0", uaddr);
tlb_op(TLB_V4_U_PAGE, "c8, c7, 1", uaddr);
tlb_op(TLB_V4_D_PAGE, "c8, c6, 1", uaddr);
tlb_op(TLB_V4_I_PAGE, "c8, c5, 1", uaddr);
if (!tlb_flag(TLB_V4_I_PAGE) && tlb_flag(TLB_V4_I_FULL))
asm("mcr p15, 0, %0, c8, c5, 0" : : "r" (zero) : "cc");
}
if (tlb_flag(TLB_V6_U_PAGE))
asm("mcr p15, 0, %0, c8, c7, 1" : : "r" (uaddr) : "cc");
if (tlb_flag(TLB_V6_D_PAGE))
asm("mcr p15, 0, %0, c8, c6, 1" : : "r" (uaddr) : "cc");
if (tlb_flag(TLB_V6_I_PAGE))
asm("mcr p15, 0, %0, c8, c5, 1" : : "r" (uaddr) : "cc");
if (tlb_flag(TLB_V7_UIS_PAGE))
tlb_op(TLB_V6_U_PAGE, "c8, c7, 1", uaddr);
tlb_op(TLB_V6_D_PAGE, "c8, c6, 1", uaddr);
tlb_op(TLB_V6_I_PAGE, "c8, c5, 1", uaddr);
#ifdef CONFIG_ARM_ERRATA_720789
asm("mcr p15, 0, %0, c8, c3, 3" : : "r" (uaddr & PAGE_MASK) : "cc");
tlb_op(TLB_V7_UIS_PAGE, "c8, c3, 3", uaddr & PAGE_MASK);
#else
asm("mcr p15, 0, %0, c8, c3, 1" : : "r" (uaddr) : "cc");
tlb_op(TLB_V7_UIS_PAGE, "c8, c3, 1", uaddr);
#endif
if (tlb_flag(TLB_BARRIER))
......@@ -432,25 +429,17 @@ static inline void local_flush_tlb_kernel_page(unsigned long kaddr)
if (tlb_flag(TLB_WB))
dsb();
if (tlb_flag(TLB_V3_PAGE))
asm("mcr p15, 0, %0, c6, c0, 0" : : "r" (kaddr) : "cc");
if (tlb_flag(TLB_V4_U_PAGE))
asm("mcr p15, 0, %0, c8, c7, 1" : : "r" (kaddr) : "cc");
if (tlb_flag(TLB_V4_D_PAGE))
asm("mcr p15, 0, %0, c8, c6, 1" : : "r" (kaddr) : "cc");
if (tlb_flag(TLB_V4_I_PAGE))
asm("mcr p15, 0, %0, c8, c5, 1" : : "r" (kaddr) : "cc");
tlb_op(TLB_V3_PAGE, "c6, c0, 0", kaddr);
tlb_op(TLB_V4_U_PAGE, "c8, c7, 1", kaddr);
tlb_op(TLB_V4_D_PAGE, "c8, c6, 1", kaddr);
tlb_op(TLB_V4_I_PAGE, "c8, c5, 1", kaddr);
if (!tlb_flag(TLB_V4_I_PAGE) && tlb_flag(TLB_V4_I_FULL))
asm("mcr p15, 0, %0, c8, c5, 0" : : "r" (zero) : "cc");
if (tlb_flag(TLB_V6_U_PAGE))
asm("mcr p15, 0, %0, c8, c7, 1" : : "r" (kaddr) : "cc");
if (tlb_flag(TLB_V6_D_PAGE))
asm("mcr p15, 0, %0, c8, c6, 1" : : "r" (kaddr) : "cc");
if (tlb_flag(TLB_V6_I_PAGE))
asm("mcr p15, 0, %0, c8, c5, 1" : : "r" (kaddr) : "cc");
if (tlb_flag(TLB_V7_UIS_PAGE))
asm("mcr p15, 0, %0, c8, c3, 1" : : "r" (kaddr) : "cc");
tlb_op(TLB_V6_U_PAGE, "c8, c7, 1", kaddr);
tlb_op(TLB_V6_D_PAGE, "c8, c6, 1", kaddr);
tlb_op(TLB_V6_I_PAGE, "c8, c5, 1", kaddr);
tlb_op(TLB_V7_UIS_PAGE, "c8, c3, 1", kaddr);
if (tlb_flag(TLB_BARRIER)) {
dsb();
......@@ -475,13 +464,8 @@ static inline void flush_pmd_entry(void *pmd)
{
const unsigned int __tlb_flag = __cpu_tlb_flags;
if (tlb_flag(TLB_DCLEAN))
asm("mcr p15, 0, %0, c7, c10, 1 @ flush_pmd"
: : "r" (pmd) : "cc");
if (tlb_flag(TLB_L2CLEAN_FR))
asm("mcr p15, 1, %0, c15, c9, 1 @ L2 flush_pmd"
: : "r" (pmd) : "cc");
tlb_op(TLB_DCLEAN, "c7, c10, 1 @ flush_pmd", pmd);
tlb_l2_op(TLB_L2CLEAN_FR, "c15, c9, 1 @ L2 flush_pmd", pmd);
if (tlb_flag(TLB_WB))
dsb();
......@@ -491,15 +475,11 @@ static inline void clean_pmd_entry(void *pmd)
{
const unsigned int __tlb_flag = __cpu_tlb_flags;
if (tlb_flag(TLB_DCLEAN))
asm("mcr p15, 0, %0, c7, c10, 1 @ flush_pmd"
: : "r" (pmd) : "cc");
if (tlb_flag(TLB_L2CLEAN_FR))
asm("mcr p15, 1, %0, c15, c9, 1 @ L2 flush_pmd"
: : "r" (pmd) : "cc");
tlb_op(TLB_DCLEAN, "c7, c10, 1 @ flush_pmd", pmd);
tlb_l2_op(TLB_L2CLEAN_FR, "c15, c9, 1 @ L2 flush_pmd", pmd);
}
#undef tlb_op
#undef tlb_flag
#undef always_tlb_flags
#undef possible_tlb_flags
......
......@@ -46,7 +46,7 @@ static inline int in_exception_text(unsigned long ptr)
return in ? : __in_irqentry_text(ptr);
}
extern void __init early_trap_init(void);
extern void __init early_trap_init(void *);
extern void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long frame);
extern void ptrace_break(struct task_struct *tsk, struct pt_regs *regs);
......
......@@ -7,6 +7,8 @@ AFLAGS_head.o := -DTEXT_OFFSET=$(TEXT_OFFSET)
ifdef CONFIG_FUNCTION_TRACER
CFLAGS_REMOVE_ftrace.o = -pg
CFLAGS_REMOVE_insn.o = -pg
CFLAGS_REMOVE_patch.o = -pg
endif
CFLAGS_REMOVE_return_address.o = -pg
......@@ -14,8 +16,8 @@ CFLAGS_REMOVE_return_address.o = -pg
# Object file lists.
obj-y := elf.o entry-armv.o entry-common.o irq.o opcodes.o \
process.o ptrace.o return_address.o setup.o signal.o \
sys_arm.o stacktrace.o time.o traps.o
process.o ptrace.o return_address.o sched_clock.o \
setup.o signal.o stacktrace.o sys_arm.o time.o traps.o
obj-$(CONFIG_DEPRECATED_PARAM_STRUCT) += compat.o
......@@ -29,14 +31,14 @@ obj-$(CONFIG_ARTHUR) += arthur.o
obj-$(CONFIG_ISA_DMA) += dma-isa.o
obj-$(CONFIG_PCI) += bios32.o isa.o
obj-$(CONFIG_ARM_CPU_SUSPEND) += sleep.o suspend.o
obj-$(CONFIG_HAVE_SCHED_CLOCK) += sched_clock.o
obj-$(CONFIG_SMP) += smp.o smp_tlb.o
obj-$(CONFIG_HAVE_ARM_SCU) += smp_scu.o
obj-$(CONFIG_HAVE_ARM_TWD) += smp_twd.o
obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o
obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o
obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o insn.o
obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o insn.o
obj-$(CONFIG_JUMP_LABEL) += jump_label.o insn.o patch.o
obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
obj-$(CONFIG_KPROBES) += kprobes.o kprobes-common.o
obj-$(CONFIG_KPROBES) += kprobes.o kprobes-common.o patch.o
ifdef CONFIG_THUMB2_KERNEL
obj-$(CONFIG_KPROBES) += kprobes-thumb.o
else
......
......@@ -100,7 +100,7 @@
#endif /* CONFIG_CPU_V6 */
#else
#elif !defined(CONFIG_DEBUG_SEMIHOSTING)
#include <mach/debug-macro.S>
#endif /* CONFIG_DEBUG_ICEDCC */
......@@ -155,6 +155,8 @@ hexbuf: .space 16
.ltorg
#ifndef CONFIG_DEBUG_SEMIHOSTING
ENTRY(printascii)
addruart_current r3, r1, r2
b 2f
......@@ -177,3 +179,24 @@ ENTRY(printch)
mov r0, #0
b 1b
ENDPROC(printch)
#else
ENTRY(printascii)
mov r1, r0
mov r0, #0x04 @ SYS_WRITE0
ARM( svc #0x123456 )
THUMB( svc #0xab )
mov pc, lr
ENDPROC(printascii)
ENTRY(printch)
adr r1, hexbuf
strb r0, [r1]
mov r0, #0x03 @ SYS_WRITEC
ARM( svc #0x123456 )
THUMB( svc #0xab )
mov pc, lr
ENDPROC(printch)
#endif
......@@ -16,10 +16,13 @@
#include <linux/uaccess.h>
#include <asm/cacheflush.h>
#include <asm/opcodes.h>
#include <asm/ftrace.h>
#include "insn.h"
#ifdef CONFIG_THUMB2_KERNEL
#define NOP 0xeb04f85d /* pop.w {lr} */
#define NOP 0xf85deb04 /* pop.w {lr} */
#else
#define NOP 0xe8bd4000 /* pop {lr} */
#endif
......@@ -60,76 +63,31 @@ static unsigned long adjust_address(struct dyn_ftrace *rec, unsigned long addr)
}
#endif
#ifdef CONFIG_THUMB2_KERNEL
static unsigned long ftrace_gen_branch(unsigned long pc, unsigned long addr,
bool link)
{
unsigned long s, j1, j2, i1, i2, imm10, imm11;
unsigned long first, second;
long offset;
offset = (long)addr - (long)(pc + 4);
if (offset < -16777216 || offset > 16777214) {
WARN_ON_ONCE(1);
return 0;
}
s = (offset >> 24) & 0x1;
i1 = (offset >> 23) & 0x1;
i2 = (offset >> 22) & 0x1;
imm10 = (offset >> 12) & 0x3ff;
imm11 = (offset >> 1) & 0x7ff;
j1 = (!i1) ^ s;
j2 = (!i2) ^ s;
first = 0xf000 | (s << 10) | imm10;
second = 0x9000 | (j1 << 13) | (j2 << 11) | imm11;
if (link)
second |= 1 << 14;
return (second << 16) | first;
}
#else
static unsigned long ftrace_gen_branch(unsigned long pc, unsigned long addr,
bool link)
{
unsigned long opcode = 0xea000000;
long offset;
if (link)
opcode |= 1 << 24;
offset = (long)addr - (long)(pc + 8);
if (unlikely(offset < -33554432 || offset > 33554428)) {
/* Can't generate branches that far (from ARM ARM). Ftrace
* doesn't generate branches outside of kernel text.
*/
WARN_ON_ONCE(1);
return 0;
}
offset = (offset >> 2) & 0x00ffffff;
return opcode | offset;
}
#endif
static unsigned long ftrace_call_replace(unsigned long pc, unsigned long addr)
{
return ftrace_gen_branch(pc, addr, true);
return arm_gen_branch_link(pc, addr);
}
static int ftrace_modify_code(unsigned long pc, unsigned long old,
unsigned long new)
unsigned long new, bool validate)
{
unsigned long replaced;
if (IS_ENABLED(CONFIG_THUMB2_KERNEL)) {
old = __opcode_to_mem_thumb32(old);
new = __opcode_to_mem_thumb32(new);
} else {
old = __opcode_to_mem_arm(old);
new = __opcode_to_mem_arm(new);
}
if (validate) {
if (probe_kernel_read(&replaced, (void *)pc, MCOUNT_INSN_SIZE))
return -EFAULT;
if (replaced != old)
return -EINVAL;
}
if (probe_kernel_write((void *)pc, &new, MCOUNT_INSN_SIZE))
return -EPERM;
......@@ -141,23 +99,21 @@ static int ftrace_modify_code(unsigned long pc, unsigned long old,
int ftrace_update_ftrace_func(ftrace_func_t func)
{
unsigned long pc, old;
unsigned long pc;
unsigned long new;
int ret;
pc = (unsigned long)&ftrace_call;
memcpy(&old, &ftrace_call, MCOUNT_INSN_SIZE);
new = ftrace_call_replace(pc, (unsigned long)func);
ret = ftrace_modify_code(pc, old, new);
ret = ftrace_modify_code(pc, 0, new, false);
#ifdef CONFIG_OLD_MCOUNT
if (!ret) {
pc = (unsigned long)&ftrace_call_old;
memcpy(&old, &ftrace_call_old, MCOUNT_INSN_SIZE);
new = ftrace_call_replace(pc, (unsigned long)func);
ret = ftrace_modify_code(pc, old, new);
ret = ftrace_modify_code(pc, 0, new, false);
}
#endif
......@@ -172,7 +128,7 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
old = ftrace_nop_replace(rec);
new = ftrace_call_replace(ip, adjust_address(rec, addr));
return ftrace_modify_code(rec->ip, old, new);
return ftrace_modify_code(rec->ip, old, new, true);
}
int ftrace_make_nop(struct module *mod,
......@@ -185,7 +141,7 @@ int ftrace_make_nop(struct module *mod,
old = ftrace_call_replace(ip, adjust_address(rec, addr));
new = ftrace_nop_replace(rec);
ret = ftrace_modify_code(ip, old, new);
ret = ftrace_modify_code(ip, old, new, true);
#ifdef CONFIG_OLD_MCOUNT
if (ret == -EINVAL && addr == MCOUNT_ADDR) {
......@@ -193,7 +149,7 @@ int ftrace_make_nop(struct module *mod,
old = ftrace_call_replace(ip, adjust_address(rec, addr));
new = ftrace_nop_replace(rec);
ret = ftrace_modify_code(ip, old, new);
ret = ftrace_modify_code(ip, old, new, true);
}
#endif
......@@ -249,12 +205,12 @@ static int __ftrace_modify_caller(unsigned long *callsite,
{
unsigned long caller_fn = (unsigned long) func;
unsigned long pc = (unsigned long) callsite;
unsigned long branch = ftrace_gen_branch(pc, caller_fn, false);
unsigned long branch = arm_gen_branch(pc, caller_fn);
unsigned long nop = 0xe1a00000; /* mov r0, r0 */
unsigned long old = enable ? nop : branch;
unsigned long new = enable ? branch : nop;
return ftrace_modify_code(pc, old, new);
return ftrace_modify_code(pc, old, new, true);
}
static int ftrace_modify_graph_caller(bool enable)
......
......@@ -265,7 +265,7 @@ __create_page_tables:
str r6, [r3]
#ifdef CONFIG_DEBUG_LL
#ifndef CONFIG_DEBUG_ICEDCC
#if !defined(CONFIG_DEBUG_ICEDCC) && !defined(CONFIG_DEBUG_SEMIHOSTING)
/*
* Map in IO space for serial debugging.
* This allows debug messages to be output
......@@ -297,10 +297,10 @@ __create_page_tables:
cmp r0, r6
blo 1b
#else /* CONFIG_DEBUG_ICEDCC */
/* we don't need any serial debugging mappings for ICEDCC */
#else /* CONFIG_DEBUG_ICEDCC || CONFIG_DEBUG_SEMIHOSTING */
/* we don't need any serial debugging mappings */
ldr r7, [r10, #PROCINFO_IO_MMUFLAGS] @ io_mmuflags
#endif /* !CONFIG_DEBUG_ICEDCC */
#endif
#if defined(CONFIG_ARCH_NETWINDER) || defined(CONFIG_ARCH_CATS)
/*
......
#include <linux/kernel.h>
#include <asm/opcodes.h>
static unsigned long
__arm_gen_branch_thumb2(unsigned long pc, unsigned long addr, bool link)
{
unsigned long s, j1, j2, i1, i2, imm10, imm11;
unsigned long first, second;
long offset;
offset = (long)addr - (long)(pc + 4);
if (offset < -16777216 || offset > 16777214) {
WARN_ON_ONCE(1);
return 0;
}
s = (offset >> 24) & 0x1;
i1 = (offset >> 23) & 0x1;
i2 = (offset >> 22) & 0x1;
imm10 = (offset >> 12) & 0x3ff;
imm11 = (offset >> 1) & 0x7ff;
j1 = (!i1) ^ s;
j2 = (!i2) ^ s;
first = 0xf000 | (s << 10) | imm10;
second = 0x9000 | (j1 << 13) | (j2 << 11) | imm11;
if (link)
second |= 1 << 14;
return __opcode_thumb32_compose(first, second);
}
static unsigned long
__arm_gen_branch_arm(unsigned long pc, unsigned long addr, bool link)
{
unsigned long opcode = 0xea000000;
long offset;
if (link)
opcode |= 1 << 24;
offset = (long)addr - (long)(pc + 8);
if (unlikely(offset < -33554432 || offset > 33554428)) {
WARN_ON_ONCE(1);
return 0;
}
offset = (offset >> 2) & 0x00ffffff;
return opcode | offset;
}
unsigned long
__arm_gen_branch(unsigned long pc, unsigned long addr, bool link)
{
if (IS_ENABLED(CONFIG_THUMB2_KERNEL))
return __arm_gen_branch_thumb2(pc, addr, link);
else
return __arm_gen_branch_arm(pc, addr, link);
}
#ifndef __ASM_ARM_INSN_H
#define __ASM_ARM_INSN_H
static inline unsigned long
arm_gen_nop(void)
{
#ifdef CONFIG_THUMB2_KERNEL
return 0xf3af8000; /* nop.w */
#else
return 0xe1a00000; /* mov r0, r0 */
#endif
}
unsigned long
__arm_gen_branch(unsigned long pc, unsigned long addr, bool link);
static inline unsigned long
arm_gen_branch(unsigned long pc, unsigned long addr)
{
return __arm_gen_branch(pc, addr, false);
}
static inline unsigned long
arm_gen_branch_link(unsigned long pc, unsigned long addr)
{
return __arm_gen_branch(pc, addr, true);
}
#endif
......@@ -180,10 +180,7 @@ void migrate_irqs(void)
local_irq_save(flags);
for_each_irq_desc(i, desc) {
bool affinity_broken = false;
if (!desc)
continue;
bool affinity_broken;
raw_spin_lock(&desc->lock);
affinity_broken = migrate_one_irq(desc);
......
#include <linux/kernel.h>
#include <linux/jump_label.h>
#include "insn.h"
#include "patch.h"
#ifdef HAVE_JUMP_LABEL
static void __arch_jump_label_transform(struct jump_entry *entry,
enum jump_label_type type,
bool is_static)
{
void *addr = (void *)entry->code;
unsigned int insn;
if (type == JUMP_LABEL_ENABLE)
insn = arm_gen_branch(entry->code, entry->target);
else
insn = arm_gen_nop();
if (is_static)
__patch_text(addr, insn);
else
patch_text(addr, insn);
}
void arch_jump_label_transform(struct jump_entry *entry,
enum jump_label_type type)
{
__arch_jump_label_transform(entry, type, false);
}
void arch_jump_label_transform_static(struct jump_entry *entry,
enum jump_label_type type)
{
__arch_jump_label_transform(entry, type, true);
}
#endif
......@@ -29,6 +29,7 @@
#include <asm/cacheflush.h>
#include "kprobes.h"
#include "patch.h"
#define MIN_STACK_SIZE(addr) \
min((unsigned long)MAX_STACK_SIZE, \
......@@ -103,57 +104,33 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
return 0;
}
#ifdef CONFIG_THUMB2_KERNEL
/*
* For a 32-bit Thumb breakpoint spanning two memory words we need to take
* special precautions to insert the breakpoint atomically, especially on SMP
* systems. This is achieved by calling this arming function using stop_machine.
*/
static int __kprobes set_t32_breakpoint(void *addr)
{
((u16 *)addr)[0] = KPROBE_THUMB32_BREAKPOINT_INSTRUCTION >> 16;
((u16 *)addr)[1] = KPROBE_THUMB32_BREAKPOINT_INSTRUCTION & 0xffff;
flush_insns(addr, 2*sizeof(u16));
return 0;
}
void __kprobes arch_arm_kprobe(struct kprobe *p)
{
uintptr_t addr = (uintptr_t)p->addr & ~1; /* Remove any Thumb flag */
if (!is_wide_instruction(p->opcode)) {
*(u16 *)addr = KPROBE_THUMB16_BREAKPOINT_INSTRUCTION;
flush_insns(addr, sizeof(u16));
} else if (addr & 2) {
/* A 32-bit instruction spanning two words needs special care */
stop_machine(set_t32_breakpoint, (void *)addr, &cpu_online_map);
} else {
/* Word aligned 32-bit instruction can be written atomically */
u32 bkp = KPROBE_THUMB32_BREAKPOINT_INSTRUCTION;
#ifndef __ARMEB__ /* Swap halfwords for little-endian */
bkp = (bkp >> 16) | (bkp << 16);
#endif
*(u32 *)addr = bkp;
flush_insns(addr, sizeof(u32));
}
}
unsigned int brkp;
void *addr;
#else /* !CONFIG_THUMB2_KERNEL */
if (IS_ENABLED(CONFIG_THUMB2_KERNEL)) {
/* Remove any Thumb flag */
addr = (void *)((uintptr_t)p->addr & ~1);
void __kprobes arch_arm_kprobe(struct kprobe *p)
{
if (is_wide_instruction(p->opcode))
brkp = KPROBE_THUMB32_BREAKPOINT_INSTRUCTION;
else
brkp = KPROBE_THUMB16_BREAKPOINT_INSTRUCTION;
} else {
kprobe_opcode_t insn = p->opcode;
kprobe_opcode_t brkp = KPROBE_ARM_BREAKPOINT_INSTRUCTION;
addr = p->addr;
brkp = KPROBE_ARM_BREAKPOINT_INSTRUCTION;
if (insn >= 0xe0000000)
brkp |= 0xe0000000; /* Unconditional instruction */
else
brkp |= insn & 0xf0000000; /* Copy condition from insn */
*p->addr = brkp;
flush_insns(p->addr, sizeof(p->addr[0]));
}
}
#endif /* !CONFIG_THUMB2_KERNEL */
patch_text(addr, brkp);
}
/*
* The actual disarming is done here on each CPU and synchronized using
......@@ -166,25 +143,10 @@ void __kprobes arch_arm_kprobe(struct kprobe *p)
int __kprobes __arch_disarm_kprobe(void *p)
{
struct kprobe *kp = p;
#ifdef CONFIG_THUMB2_KERNEL
u16 *addr = (u16 *)((uintptr_t)kp->addr & ~1);
kprobe_opcode_t insn = kp->opcode;
unsigned int len;
void *addr = (void *)((uintptr_t)kp->addr & ~1);
if (is_wide_instruction(insn)) {
((u16 *)addr)[0] = insn>>16;
((u16 *)addr)[1] = insn;
len = 2*sizeof(u16);
} else {
((u16 *)addr)[0] = insn;
len = sizeof(u16);
}
flush_insns(addr, len);
__patch_text(addr, kp->opcode);
#else /* !CONFIG_THUMB2_KERNEL */
*kp->addr = kp->opcode;
flush_insns(kp->addr, sizeof(kp->addr[0]));
#endif
return 0;
}
......
......@@ -7,6 +7,7 @@
#include <linux/delay.h>
#include <linux/reboot.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <asm/pgtable.h>
#include <asm/pgalloc.h>
#include <asm/mmu_context.h>
......@@ -53,6 +54,29 @@ void machine_crash_nonpanic_core(void *unused)
cpu_relax();
}
static void machine_kexec_mask_interrupts(void)
{
unsigned int i;
struct irq_desc *desc;
for_each_irq_desc(i, desc) {
struct irq_chip *chip;
chip = irq_desc_get_chip(desc);
if (!chip)
continue;
if (chip->irq_eoi && irqd_irq_inprogress(&desc->irq_data))
chip->irq_eoi(&desc->irq_data);
if (chip->irq_mask)
chip->irq_mask(&desc->irq_data);
if (chip->irq_disable && !irqd_irq_disabled(&desc->irq_data))
chip->irq_disable(&desc->irq_data);
}
}
void machine_crash_shutdown(struct pt_regs *regs)
{
unsigned long msecs;
......@@ -70,6 +94,7 @@ void machine_crash_shutdown(struct pt_regs *regs)
printk(KERN_WARNING "Non-crashing CPUs did not react to IPI\n");
crash_save_cpu(regs, smp_processor_id());
machine_kexec_mask_interrupts();
printk(KERN_INFO "Loading crashdump kernel...\n");
}
......
#include <linux/kernel.h>
#include <linux/kprobes.h>
#include <linux/stop_machine.h>
#include <asm/cacheflush.h>
#include <asm/smp_plat.h>
#include <asm/opcodes.h>
#include "patch.h"
struct patch {
void *addr;
unsigned int insn;
};
void __kprobes __patch_text(void *addr, unsigned int insn)
{
bool thumb2 = IS_ENABLED(CONFIG_THUMB2_KERNEL);
int size;
if (thumb2 && __opcode_is_thumb16(insn)) {
*(u16 *)addr = __opcode_to_mem_thumb16(insn);
size = sizeof(u16);
} else if (thumb2 && ((uintptr_t)addr & 2)) {
u16 first = __opcode_thumb32_first(insn);
u16 second = __opcode_thumb32_second(insn);
u16 *addrh = addr;
addrh[0] = __opcode_to_mem_thumb16(first);
addrh[1] = __opcode_to_mem_thumb16(second);
size = sizeof(u32);
} else {
if (thumb2)
insn = __opcode_to_mem_thumb32(insn);
else
insn = __opcode_to_mem_arm(insn);
*(u32 *)addr = insn;
size = sizeof(u32);
}
flush_icache_range((uintptr_t)(addr),
(uintptr_t)(addr) + size);
}
static int __kprobes patch_text_stop_machine(void *data)
{
struct patch *patch = data;
__patch_text(patch->addr, patch->insn);
return 0;
}
void __kprobes patch_text(void *addr, unsigned int insn)
{
struct patch patch = {
.addr = addr,
.insn = insn,
};
if (cache_ops_need_broadcast()) {
stop_machine(patch_text_stop_machine, &patch, cpu_online_mask);
} else {
bool straddles_word = IS_ENABLED(CONFIG_THUMB2_KERNEL)
&& __opcode_is_thumb32(insn)
&& ((uintptr_t)addr & 2);
if (straddles_word)
stop_machine(patch_text_stop_machine, &patch, NULL);
else
__patch_text(addr, insn);
}
}
#ifndef _ARM_KERNEL_PATCH_H
#define _ARM_KERNEL_PATCH_H
void patch_text(void *addr, unsigned int insn);
void __patch_text(void *addr, unsigned int insn);
#endif
......@@ -738,6 +738,9 @@ init_hw_perf_events(void)
case 0xC0F0: /* Cortex-A15 */
cpu_pmu = armv7_a15_pmu_init();
break;
case 0xC070: /* Cortex-A7 */
cpu_pmu = armv7_a7_pmu_init();
break;
}
/* Intel CPUs [xscale]. */
} else if (0x69 == implementor) {
......
......@@ -609,6 +609,130 @@ static const unsigned armv7_a15_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
},
};
/*
* Cortex-A7 HW events mapping
*/
static const unsigned armv7_a7_perf_map[PERF_COUNT_HW_MAX] = {
[PERF_COUNT_HW_CPU_CYCLES] = ARMV7_PERFCTR_CPU_CYCLES,
[PERF_COUNT_HW_INSTRUCTIONS] = ARMV7_PERFCTR_INSTR_EXECUTED,
[PERF_COUNT_HW_CACHE_REFERENCES] = ARMV7_PERFCTR_L1_DCACHE_ACCESS,
[PERF_COUNT_HW_CACHE_MISSES] = ARMV7_PERFCTR_L1_DCACHE_REFILL,
[PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = ARMV7_PERFCTR_PC_WRITE,
[PERF_COUNT_HW_BRANCH_MISSES] = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED,
[PERF_COUNT_HW_BUS_CYCLES] = ARMV7_PERFCTR_BUS_CYCLES,
[PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = HW_OP_UNSUPPORTED,
[PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = HW_OP_UNSUPPORTED,
};
static const unsigned armv7_a7_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
[PERF_COUNT_HW_CACHE_OP_MAX]
[PERF_COUNT_HW_CACHE_RESULT_MAX] = {
[C(L1D)] = {
/*
* The performance counters don't differentiate between read
* and write accesses/misses so this isn't strictly correct,
* but it's the best we can do. Writes and reads get
* combined.
*/
[C(OP_READ)] = {
[C(RESULT_ACCESS)] = ARMV7_PERFCTR_L1_DCACHE_ACCESS,
[C(RESULT_MISS)] = ARMV7_PERFCTR_L1_DCACHE_REFILL,
},
[C(OP_WRITE)] = {
[C(RESULT_ACCESS)] = ARMV7_PERFCTR_L1_DCACHE_ACCESS,
[C(RESULT_MISS)] = ARMV7_PERFCTR_L1_DCACHE_REFILL,
},
[C(OP_PREFETCH)] = {
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
},
},
[C(L1I)] = {
[C(OP_READ)] = {
[C(RESULT_ACCESS)] = ARMV7_PERFCTR_L1_ICACHE_ACCESS,
[C(RESULT_MISS)] = ARMV7_PERFCTR_L1_ICACHE_REFILL,
},
[C(OP_WRITE)] = {
[C(RESULT_ACCESS)] = ARMV7_PERFCTR_L1_ICACHE_ACCESS,
[C(RESULT_MISS)] = ARMV7_PERFCTR_L1_ICACHE_REFILL,
},
[C(OP_PREFETCH)] = {
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
},
},
[C(LL)] = {
[C(OP_READ)] = {
[C(RESULT_ACCESS)] = ARMV7_PERFCTR_L2_CACHE_ACCESS,
[C(RESULT_MISS)] = ARMV7_PERFCTR_L2_CACHE_REFILL,
},
[C(OP_WRITE)] = {
[C(RESULT_ACCESS)] = ARMV7_PERFCTR_L2_CACHE_ACCESS,
[C(RESULT_MISS)] = ARMV7_PERFCTR_L2_CACHE_REFILL,
},
[C(OP_PREFETCH)] = {
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
},
},
[C(DTLB)] = {
[C(OP_READ)] = {
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
[C(RESULT_MISS)] = ARMV7_PERFCTR_DTLB_REFILL,
},
[C(OP_WRITE)] = {
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
[C(RESULT_MISS)] = ARMV7_PERFCTR_DTLB_REFILL,
},
[C(OP_PREFETCH)] = {
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
},
},
[C(ITLB)] = {
[C(OP_READ)] = {
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
[C(RESULT_MISS)] = ARMV7_PERFCTR_ITLB_REFILL,
},
[C(OP_WRITE)] = {
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
[C(RESULT_MISS)] = ARMV7_PERFCTR_ITLB_REFILL,
},
[C(OP_PREFETCH)] = {
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
},
},
[C(BPU)] = {
[C(OP_READ)] = {
[C(RESULT_ACCESS)] = ARMV7_PERFCTR_PC_BRANCH_PRED,
[C(RESULT_MISS)] = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED,
},
[C(OP_WRITE)] = {
[C(RESULT_ACCESS)] = ARMV7_PERFCTR_PC_BRANCH_PRED,
[C(RESULT_MISS)] = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED,
},
[C(OP_PREFETCH)] = {
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
},
},
[C(NODE)] = {
[C(OP_READ)] = {
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
},
[C(OP_WRITE)] = {
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
},
[C(OP_PREFETCH)] = {
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
},
},
};
/*
* Perf Events' indices
*/
......@@ -1104,6 +1228,12 @@ static int armv7_a15_map_event(struct perf_event *event)
&armv7_a15_perf_cache_map, 0xFF);
}
static int armv7_a7_map_event(struct perf_event *event)
{
return map_cpu_event(event, &armv7_a7_perf_map,
&armv7_a7_perf_cache_map, 0xFF);
}
static struct arm_pmu armv7pmu = {
.handle_irq = armv7pmu_handle_irq,
.enable = armv7pmu_enable_event,
......@@ -1164,6 +1294,16 @@ static struct arm_pmu *__init armv7_a15_pmu_init(void)
armv7pmu.set_event_filter = armv7pmu_set_event_filter;
return &armv7pmu;
}
static struct arm_pmu *__init armv7_a7_pmu_init(void)
{
armv7pmu.id = ARM_PERF_PMU_ID_CA7;
armv7pmu.name = "ARMv7 Cortex-A7";
armv7pmu.map_event = armv7_a7_map_event;
armv7pmu.num_events = armv7_read_num_pmnc_events();
armv7pmu.set_event_filter = armv7pmu_set_event_filter;
return &armv7pmu;
}
#else
static struct arm_pmu *__init armv7_a8_pmu_init(void)
{
......@@ -1184,4 +1324,9 @@ static struct arm_pmu *__init armv7_a15_pmu_init(void)
{
return NULL;
}
static struct arm_pmu *__init armv7_a7_pmu_init(void)
{
return NULL;
}
#endif /* CONFIG_CPU_V7 */
......@@ -528,21 +528,39 @@ unsigned long arch_randomize_brk(struct mm_struct *mm)
#ifdef CONFIG_MMU
/*
* The vectors page is always readable from user space for the
* atomic helpers and the signal restart code. Let's declare a mapping
* for it so it is visible through ptrace and /proc/<pid>/mem.
* atomic helpers and the signal restart code. Insert it into the
* gate_vma so that it is visible through ptrace and /proc/<pid>/mem.
*/
static struct vm_area_struct gate_vma;
int vectors_user_mapping(void)
static int __init gate_vma_init(void)
{
struct mm_struct *mm = current->mm;
return install_special_mapping(mm, 0xffff0000, PAGE_SIZE,
VM_READ | VM_EXEC |
VM_MAYREAD | VM_MAYEXEC | VM_RESERVED,
NULL);
gate_vma.vm_start = 0xffff0000;
gate_vma.vm_end = 0xffff0000 + PAGE_SIZE;
gate_vma.vm_page_prot = PAGE_READONLY_EXEC;
gate_vma.vm_flags = VM_READ | VM_EXEC |
VM_MAYREAD | VM_MAYEXEC;
return 0;
}
arch_initcall(gate_vma_init);
struct vm_area_struct *get_gate_vma(struct mm_struct *mm)
{
return &gate_vma;
}
int in_gate_area(struct mm_struct *mm, unsigned long addr)
{
return (addr >= gate_vma.vm_start) && (addr < gate_vma.vm_end);
}
int in_gate_area_no_mm(unsigned long addr)
{
return in_gate_area(NULL, addr);
}
const char *arch_vma_name(struct vm_area_struct *vma)
{
return (vma->vm_start == 0xffff0000) ? "[vectors]" : NULL;
return (vma == &gate_vma) ? "[vectors]" : NULL;
}
#endif
......@@ -10,6 +10,7 @@
#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/syscore_ops.h>
#include <linux/timer.h>
#include <asm/sched_clock.h>
......@@ -164,3 +165,20 @@ void __init sched_clock_postinit(void)
sched_clock_poll(sched_clock_timer.data);
}
static int sched_clock_suspend(void)
{
sched_clock_poll(sched_clock_timer.data);
return 0;
}
static struct syscore_ops sched_clock_ops = {
.suspend = sched_clock_suspend,
};
static int __init sched_clock_syscore_init(void)
{
register_syscore_ops(&sched_clock_ops);
return 0;
}
device_initcall(sched_clock_syscore_init);
......@@ -976,7 +976,6 @@ void __init setup_arch(char **cmdline_p)
conswitchp = &dummy_con;
#endif
#endif
early_trap_init();
if (mdesc->init_early)
mdesc->init_early();
......
......@@ -66,12 +66,13 @@ const unsigned long syscall_restart_code[2] = {
*/
asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, old_sigset_t mask)
{
mask &= _BLOCKABLE;
spin_lock_irq(&current->sighand->siglock);
sigset_t blocked;
current->saved_sigmask = current->blocked;
siginitset(&current->blocked, mask);
recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
mask &= _BLOCKABLE;
siginitset(&blocked, mask);
set_current_blocked(&blocked);
current->state = TASK_INTERRUPTIBLE;
schedule();
......@@ -280,10 +281,7 @@ static int restore_sigframe(struct pt_regs *regs, struct sigframe __user *sf)
err = __copy_from_user(&set, &sf->uc.uc_sigmask, sizeof(set));
if (err == 0) {
sigdelsetmask(&set, ~_BLOCKABLE);
spin_lock_irq(&current->sighand->siglock);
current->blocked = set;
recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
set_current_blocked(&set);
}
__get_user_error(regs->ARM_r0, &sf->uc.uc_mcontext.arm_r0, err);
......@@ -636,13 +634,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,
/*
* Block the signal if we were successful.
*/
spin_lock_irq(&tsk->sighand->siglock);
sigorsets(&tsk->blocked, &tsk->blocked,
&ka->sa.sa_mask);
if (!(ka->sa.sa_flags & SA_NODEFER))
sigaddset(&tsk->blocked, sig);
recalc_sigpending();
spin_unlock_irq(&tsk->sighand->siglock);
block_sigmask(ka, sig);
return 0;
}
......
......@@ -58,6 +58,8 @@ enum ipi_msg_type {
IPI_CPU_STOP,
};
static DECLARE_COMPLETION(cpu_running);
int __cpuinit __cpu_up(unsigned int cpu)
{
struct cpuinfo_arm *ci = &per_cpu(cpu_data, cpu);
......@@ -98,20 +100,12 @@ int __cpuinit __cpu_up(unsigned int cpu)
*/
ret = boot_secondary(cpu, idle);
if (ret == 0) {
unsigned long timeout;
/*
* CPU was successfully started, wait for it
* to come online or time out.
*/
timeout = jiffies + HZ;
while (time_before(jiffies, timeout)) {
if (cpu_online(cpu))
break;
udelay(10);
barrier();
}
wait_for_completion_timeout(&cpu_running,
msecs_to_jiffies(1000));
if (!cpu_online(cpu)) {
pr_crit("CPU%u: failed to come online\n", cpu);
......@@ -288,9 +282,10 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
/*
* OK, now it's safe to let the boot CPU continue. Wait for
* the CPU migration code to notice that the CPU is online
* before we continue.
* before we continue - which happens after __cpu_up returns.
*/
set_cpu_online(cpu, true);
complete(&cpu_running);
/*
* Setup the percpu timer for this CPU.
......
......@@ -25,8 +25,6 @@
#include <linux/timer.h>
#include <linux/irq.h>
#include <linux/mc146818rtc.h>
#include <asm/leds.h>
#include <asm/thread_info.h>
#include <asm/sched_clock.h>
......@@ -149,8 +147,6 @@ void __init time_init(void)
{
system_timer = machine_desc->timer;
system_timer->init();
#ifdef CONFIG_HAVE_SCHED_CLOCK
sched_clock_postinit();
#endif
}
......@@ -227,6 +227,11 @@ void show_stack(struct task_struct *tsk, unsigned long *sp)
#else
#define S_SMP ""
#endif
#ifdef CONFIG_THUMB2_KERNEL
#define S_ISA " THUMB2"
#else
#define S_ISA " ARM"
#endif
static int __die(const char *str, int err, struct thread_info *thread, struct pt_regs *regs)
{
......@@ -234,8 +239,8 @@ static int __die(const char *str, int err, struct thread_info *thread, struct pt
static int die_counter;
int ret;
printk(KERN_EMERG "Internal error: %s: %x [#%d]" S_PREEMPT S_SMP "\n",
str, err, ++die_counter);
printk(KERN_EMERG "Internal error: %s: %x [#%d]" S_PREEMPT S_SMP
S_ISA "\n", str, err, ++die_counter);
/* trap and error numbers are mostly meaningless on ARM */
ret = notify_die(DIE_OOPS, str, regs, err, tsk->thread.trap_no, SIGSEGV);
......@@ -784,18 +789,16 @@ static void __init kuser_get_tls_init(unsigned long vectors)
memcpy((void *)vectors + 0xfe0, (void *)vectors + 0xfe8, 4);
}
void __init early_trap_init(void)
void __init early_trap_init(void *vectors_base)
{
#if defined(CONFIG_CPU_USE_DOMAINS)
unsigned long vectors = CONFIG_VECTORS_BASE;
#else
unsigned long vectors = (unsigned long)vectors_page;
#endif
unsigned long vectors = (unsigned long)vectors_base;
extern char __stubs_start[], __stubs_end[];
extern char __vectors_start[], __vectors_end[];
extern char __kuser_helper_start[], __kuser_helper_end[];
int kuser_sz = __kuser_helper_end - __kuser_helper_start;
vectors_page = vectors_base;
/*
* Copy the vectors, stubs and kuser helpers (in entry-armv.S)
* into the vector page, mapped at 0xffff0000, and ensure these
......
......@@ -19,11 +19,14 @@
#include <linux/err.h>
#include <linux/platform_device.h>
#include <mach/hardware.h>
#include <asm/sched_clock.h>
#include <asm/mach/irq.h>
#include <asm/mach/time.h>
#include <mach/cputype.h>
#include <mach/hardware.h>
#include <mach/time.h>
#include "clock.h"
static struct clock_event_device clockevent_davinci;
......@@ -272,19 +275,9 @@ static cycle_t read_cycles(struct clocksource *cs)
return (cycles_t)timer32_read(t);
}
/*
* Kernel assumes that sched_clock can be called early but may not have
* things ready yet.
*/
static cycle_t read_dummy(struct clocksource *cs)
{
return 0;
}
static struct clocksource clocksource_davinci = {
.rating = 300,
.read = read_dummy,
.read = read_cycles,
.mask = CLOCKSOURCE_MASK(32),
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
......@@ -292,12 +285,9 @@ static struct clocksource clocksource_davinci = {
/*
* Overwrite weak default sched_clock with something more precise
*/
unsigned long long notrace sched_clock(void)
static u32 notrace davinci_read_sched_clock(void)
{
const cycle_t cyc = clocksource_davinci.read(&clocksource_davinci);
return clocksource_cyc2ns(cyc, clocksource_davinci.mult,
clocksource_davinci.shift);
return timer32_read(&timers[TID_CLOCKSOURCE]);
}
/*
......@@ -397,12 +387,14 @@ static void __init davinci_timer_init(void)
davinci_clock_tick_rate = clk_get_rate(timer_clk);
/* setup clocksource */
clocksource_davinci.read = read_cycles;
clocksource_davinci.name = id_to_name[clocksource_id];
if (clocksource_register_hz(&clocksource_davinci,
davinci_clock_tick_rate))
printk(err, clocksource_davinci.name);
setup_sched_clock(davinci_read_sched_clock, 32,
davinci_clock_tick_rate);
/* setup clockevent */
clockevent_davinci.name = id_to_name[timers[TID_CLOCKEVENT].id];
clockevent_davinci.mult = div_sc(davinci_clock_tick_rate, NSEC_PER_SEC,
......
......@@ -35,7 +35,6 @@
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/mach/time.h>
#include <mach/irqs.h>
#include "core.h"
#include "sysregs.h"
......
#ifndef __MACH_IRQS_H
#define __MACH_IRQS_H
#define NR_IRQS 192
#endif
......@@ -25,8 +25,9 @@
#include <mach/hardware.h>
#include <mach/platform.h>
#include <asm/irq.h>
#include <mach/cm.h>
#include <mach/irqs.h>
#include <asm/leds.h>
#include <asm/mach-types.h>
#include <asm/mach/time.h>
......
......@@ -78,5 +78,6 @@
#define IRQ_SIC_CP_LMINT7 46
#define IRQ_SIC_END 46
#define NR_IRQS 47
#define NR_IRQS_INTEGRATOR_AP 34
#define NR_IRQS_INTEGRATOR_CP 47
......@@ -38,12 +38,13 @@
#include <mach/hardware.h>
#include <mach/platform.h>
#include <asm/hardware/arm_timer.h>
#include <asm/irq.h>
#include <asm/setup.h>
#include <asm/param.h> /* HZ */
#include <asm/mach-types.h>
#include <asm/sched_clock.h>
#include <mach/lm.h>
#include <mach/irqs.h>
#include <asm/mach/arch.h>
#include <asm/mach/irq.h>
......@@ -325,6 +326,11 @@ static void __init ap_init(void)
static unsigned long timer_reload;
static u32 notrace integrator_read_sched_clock(void)
{
return -readl((void __iomem *) TIMER2_VA_BASE + TIMER_VALUE);
}
static void integrator_clocksource_init(unsigned long inrate)
{
void __iomem *base = (void __iomem *)TIMER2_VA_BASE;
......@@ -341,6 +347,7 @@ static void integrator_clocksource_init(unsigned long inrate)
clocksource_mmio_init(base + TIMER_VALUE, "timer2",
rate, 200, 16, clocksource_mmio_readl_down);
setup_sched_clock(integrator_read_sched_clock, 16, rate);
}
static void __iomem * const clkevt_base = (void __iomem *)TIMER1_VA_BASE;
......@@ -468,6 +475,7 @@ MACHINE_START(INTEGRATOR, "ARM-Integrator")
.atag_offset = 0x100,
.reserve = integrator_reserve,
.map_io = ap_map_io,
.nr_irqs = NR_IRQS_INTEGRATOR_AP,
.init_early = integrator_init_early,
.init_irq = ap_init_irq,
.timer = &ap_timer,
......
......@@ -26,7 +26,6 @@
#include <mach/hardware.h>
#include <mach/platform.h>
#include <asm/irq.h>
#include <asm/setup.h>
#include <asm/mach-types.h>
#include <asm/hardware/arm_timer.h>
......@@ -34,6 +33,7 @@
#include <mach/cm.h>
#include <mach/lm.h>
#include <mach/irqs.h>
#include <asm/mach/arch.h>
#include <asm/mach/irq.h>
......@@ -464,6 +464,7 @@ MACHINE_START(CINTEGRATOR, "ARM-IntegratorCP")
.atag_offset = 0x100,
.reserve = integrator_reserve,
.map_io = intcp_map_io,
.nr_irqs = NR_IRQS_INTEGRATOR_CP,
.init_early = intcp_init_early,
.init_irq = intcp_init_irq,
.timer = &cp_timer,
......
......@@ -26,10 +26,11 @@
#include <linux/interrupt.h>
#include <linux/init.h>
#include <asm/irq.h>
#include <asm/mach/pci.h>
#include <asm/mach-types.h>
#include <mach/irqs.h>
/*
* A small note about bridges and interrupts. The DECchip 21050 (and
* later) adheres to the PCI-PCI bridge specification. This says that
......
......@@ -30,7 +30,8 @@
#include <mach/hardware.h>
#include <mach/platform.h>
#include <asm/irq.h>
#include <mach/irqs.h>
#include <asm/signal.h>
#include <asm/mach/pci.h>
#include <asm/irq_regs.h>
......
......@@ -23,6 +23,7 @@
#include <mach/addr-map.h>
#include <mach/mfp-pxa168.h>
#include <mach/pxa168.h>
#include <mach/irqs.h>
#include <video/pxa168fb.h>
#include <linux/input.h>
#include <plat/pxa27x_keypad.h>
......@@ -239,7 +240,7 @@ static void __init common_init(void)
MACHINE_START(ASPENITE, "PXA168-based Aspenite Development Platform")
.map_io = mmp_map_io,
.nr_irqs = IRQ_BOARD_START,
.nr_irqs = MMP_NR_IRQS,
.init_irq = pxa168_init_irq,
.timer = &pxa168_timer,
.init_machine = common_init,
......@@ -248,7 +249,7 @@ MACHINE_END
MACHINE_START(ZYLONITE2, "PXA168-based Zylonite2 Development Platform")
.map_io = mmp_map_io,
.nr_irqs = IRQ_BOARD_START,
.nr_irqs = MMP_NR_IRQS,
.init_irq = pxa168_init_irq,
.timer = &pxa168_timer,
.init_machine = common_init,
......
......@@ -43,6 +43,7 @@ static void __init avengers_lite_init(void)
MACHINE_START(AVENGERS_LITE, "PXA168 Avengers lite Development Platform")
.map_io = mmp_map_io,
.nr_irqs = MMP_NR_IRQS,
.init_irq = pxa168_init_irq,
.timer = &pxa168_timer,
.init_machine = avengers_lite_init,
......
......@@ -28,7 +28,7 @@
#include "common.h"
#define BROWNSTONE_NR_IRQS (IRQ_BOARD_START + 40)
#define BROWNSTONE_NR_IRQS (MMP_NR_IRQS + 40)
#define GPIO_5V_ENABLE (89)
......@@ -158,7 +158,7 @@ static struct platform_device brownstone_v_5vp_device = {
};
static struct max8925_platform_data brownstone_max8925_info = {
.irq_base = IRQ_BOARD_START,
.irq_base = MMP_NR_IRQS,
};
static struct i2c_board_info brownstone_twsi1_info[] = {
......
......@@ -23,10 +23,11 @@
#include <mach/addr-map.h>
#include <mach/mfp-mmp2.h>
#include <mach/mmp2.h>
#include <mach/irqs.h>
#include "common.h"
#define FLINT_NR_IRQS (IRQ_BOARD_START + 48)
#define FLINT_NR_IRQS (MMP_NR_IRQS + 48)
static unsigned long flint_pin_config[] __initdata = {
/* UART1 */
......
......@@ -191,7 +191,7 @@ static void __init gplugd_init(void)
MACHINE_START(GPLUGD, "PXA168-based GuruPlug Display (gplugD) Platform")
.map_io = mmp_map_io,
.nr_irqs = IRQ_BOARD_START,
.nr_irqs = MMP_NR_IRQS,
.init_irq = pxa168_init_irq,
.timer = &pxa168_timer,
.init_machine = gplugd_init,
......
......@@ -223,7 +223,6 @@
#define MMP_GPIO_TO_IRQ(gpio) (IRQ_GPIO_START + (gpio))
#define IRQ_BOARD_START (IRQ_GPIO_START + MMP_NR_BUILTIN_GPIO)
#define NR_IRQS (IRQ_BOARD_START)
#define MMP_NR_IRQS IRQ_BOARD_START
#endif /* __ASM_MACH_IRQS_H */
......@@ -15,6 +15,7 @@
#include <linux/irq.h>
#include <linux/io.h>
#include <mach/irqs.h>
#include <mach/regs-icu.h>
#include <mach/mmp2.h>
......
......@@ -19,6 +19,7 @@
#include <linux/mfd/max8925.h>
#include <linux/interrupt.h>
#include <mach/irqs.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <mach/addr-map.h>
......@@ -27,7 +28,7 @@
#include "common.h"
#define JASPER_NR_IRQS (IRQ_BOARD_START + 48)
#define JASPER_NR_IRQS (MMP_NR_IRQS + 48)
static unsigned long jasper_pin_config[] __initdata = {
/* UART1 */
......@@ -135,7 +136,7 @@ static struct max8925_power_pdata jasper_power_data = {
static struct max8925_platform_data jasper_max8925_info = {
.backlight = &jasper_backlight_data,
.power = &jasper_power_data,
.irq_base = IRQ_BOARD_START,
.irq_base = MMP_NR_IRQS,
};
static struct i2c_board_info jasper_twsi1_info[] = {
......
......@@ -101,6 +101,7 @@ static void __init tavorevb_init(void)
MACHINE_START(TAVOREVB, "PXA910 Evaluation Board (aka TavorEVB)")
.map_io = mmp_map_io,
.nr_irqs = MMP_NR_IRQS,
.init_irq = pxa910_init_irq,
.timer = &pxa910_timer,
.init_machine = tavorevb_init,
......
......@@ -26,6 +26,7 @@
#include <mach/mfp-pxa168.h>
#include <mach/pxa168.h>
#include <mach/teton_bga.h>
#include <mach/irqs.h>
#include "common.h"
......@@ -83,7 +84,7 @@ static void __init teton_bga_init(void)
MACHINE_START(TETON_BGA, "PXA168-based Teton BGA Development Platform")
.map_io = mmp_map_io,
.nr_irqs = IRQ_BOARD_START,
.nr_irqs = MMP_NR_IRQS,
.init_irq = pxa168_init_irq,
.timer = &pxa168_timer,
.init_machine = teton_bga_init,
......
......@@ -38,7 +38,7 @@
* 16 board interrupts -- PCA9575 GPIO expander
* 24 board interrupts -- 88PM860x PMIC
*/
#define TTCDKB_NR_IRQS (IRQ_BOARD_START + 16 + 16 + 24)
#define TTCDKB_NR_IRQS (MMP_NR_IRQS + 16 + 16 + 24)
static unsigned long ttc_dkb_pin_config[] __initdata = {
/* UART2 */
......@@ -131,7 +131,7 @@ static struct platform_device *ttc_dkb_devices[] = {
static struct pca953x_platform_data max7312_data[] = {
{
.gpio_base = TTCDKB_GPIO_EXT0(0),
.irq_base = IRQ_BOARD_START,
.irq_base = MMP_NR_IRQS,
},
};
......
......@@ -24,6 +24,7 @@
#include <asm/mach/time.h>
#include <asm/hardware/gic.h>
#include <asm/localtimer.h>
#include <asm/sched_clock.h>
#include <mach/msm_iomap.h>
#include <mach/cpu.h>
......@@ -105,12 +106,12 @@ static union {
static void __iomem *source_base;
static cycle_t msm_read_timer_count(struct clocksource *cs)
static notrace cycle_t msm_read_timer_count(struct clocksource *cs)
{
return readl_relaxed(source_base + TIMER_COUNT_VAL);
}
static cycle_t msm_read_timer_count_shift(struct clocksource *cs)
static notrace cycle_t msm_read_timer_count_shift(struct clocksource *cs)
{
/*
* Shift timer count down by a constant due to unreliable lower bits
......@@ -166,6 +167,11 @@ static struct local_timer_ops msm_local_timer_ops __cpuinitdata = {
};
#endif /* CONFIG_LOCAL_TIMERS */
static notrace u32 msm_sched_clock_read(void)
{
return msm_clocksource.read(&msm_clocksource);
}
static void __init msm_timer_init(void)
{
struct clock_event_device *ce = &msm_clockevent;
......@@ -232,6 +238,8 @@ static void __init msm_timer_init(void)
res = clocksource_register_hz(cs, dgt_hz);
if (res)
pr_err("clocksource_register failed\n");
setup_sched_clock(msm_sched_clock_read,
cpu_is_msm7x01() ? 32 - MSM_DGT_SHIFT : 32, dgt_hz);
}
struct sys_timer msm_timer = {
......
/*
* Copyright (c) 2011 Picochip Ltd., Jamie Iles
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef __MACH_IRQS_H
#define __MACH_IRQS_H
/* We dynamically allocate our irq_desc's. */
#define NR_IRQS 0
#endif /* __MACH_IRQS_H */
......@@ -18,6 +18,7 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <mach/map.h>
#include <asm/sched_clock.h>
#include <asm/mach/time.h>
#define SIRFSOC_TIMER_COUNTER_LO 0x0000
......@@ -165,21 +166,9 @@ static struct irqaction sirfsoc_timer_irq = {
};
/* Overwrite weak default sched_clock with more precise one */
unsigned long long notrace sched_clock(void)
static u32 notrace sirfsoc_read_sched_clock(void)
{
static int is_mapped;
/*
* sched_clock is called earlier than .init of sys_timer
* if we map timer memory in .init of sys_timer, system
* will panic due to illegal memory access
*/
if (!is_mapped) {
sirfsoc_of_timer_map();
is_mapped = 1;
}
return sirfsoc_timer_read(NULL) * (NSEC_PER_SEC / CLOCK_TICK_RATE);
return (u32)(sirfsoc_timer_read(NULL) & 0xffffffff);
}
static void __init sirfsoc_clockevent_init(void)
......@@ -210,6 +199,8 @@ static void __init sirfsoc_timer_init(void)
BUG_ON(rate < CLOCK_TICK_RATE);
BUG_ON(rate % CLOCK_TICK_RATE);
sirfsoc_of_timer_map();
writel_relaxed(rate / CLOCK_TICK_RATE / 2 - 1, sirfsoc_timer_base + SIRFSOC_TIMER_DIV);
writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_LO);
writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_HI);
......@@ -217,6 +208,8 @@ static void __init sirfsoc_timer_init(void)
BUG_ON(clocksource_register_hz(&sirfsoc_clocksource, CLOCK_TICK_RATE));
setup_sched_clock(sirfsoc_read_sched_clock, 32, CLOCK_TICK_RATE);
BUG_ON(setup_irq(sirfsoc_timer_irq.irq, &sirfsoc_timer_irq));
sirfsoc_clockevent_init();
......
......@@ -150,6 +150,7 @@ MACHINE_START(CAPC7117,
"Embedian CAPC-7117 evaluation kit based on the MXM-8x10 CoM")
.atag_offset = 0x100,
.map_io = pxa3xx_map_io,
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa3xx_init_irq,
.handle_irq = pxa3xx_handle_irq,
.timer = &pxa_timer,
......
......@@ -854,6 +854,7 @@ static void __init cm_x300_fixup(struct tag *tags, char **cmdline,
MACHINE_START(CM_X300, "CM-X300 module")
.atag_offset = 0x100,
.map_io = pxa3xx_map_io,
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa3xx_init_irq,
.handle_irq = pxa3xx_handle_irq,
.timer = &pxa_timer,
......
......@@ -310,6 +310,7 @@ MACHINE_START(COLIBRI, "Toradex Colibri PXA270")
.atag_offset = 0x100,
.init_machine = colibri_pxa270_init,
.map_io = pxa27x_map_io,
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa27x_init_irq,
.handle_irq = pxa27x_handle_irq,
.timer = &pxa_timer,
......@@ -320,6 +321,7 @@ MACHINE_START(INCOME, "Income s.r.o. SH-Dmaster PXA270 SBC")
.atag_offset = 0x100,
.init_machine = colibri_pxa270_income_init,
.map_io = pxa27x_map_io,
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa27x_init_irq,
.handle_irq = pxa27x_handle_irq,
.timer = &pxa_timer,
......
......@@ -186,6 +186,7 @@ MACHINE_START(COLIBRI300, "Toradex Colibri PXA300")
.atag_offset = 0x100,
.init_machine = colibri_pxa300_init,
.map_io = pxa3xx_map_io,
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa3xx_init_irq,
.handle_irq = pxa3xx_handle_irq,
.timer = &pxa_timer,
......
......@@ -256,6 +256,7 @@ MACHINE_START(COLIBRI320, "Toradex Colibri PXA320")
.atag_offset = 0x100,
.init_machine = colibri_pxa320_init,
.map_io = pxa3xx_map_io,
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa3xx_init_irq,
.handle_irq = pxa3xx_handle_irq,
.timer = &pxa_timer,
......
......@@ -729,6 +729,7 @@ static void __init fixup_corgi(struct tag *tags, char **cmdline,
MACHINE_START(CORGI, "SHARP Corgi")
.fixup = fixup_corgi,
.map_io = pxa25x_map_io,
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa25x_init_irq,
.handle_irq = pxa25x_handle_irq,
.init_machine = corgi_init,
......@@ -741,6 +742,7 @@ MACHINE_END
MACHINE_START(SHEPHERD, "SHARP Shepherd")
.fixup = fixup_corgi,
.map_io = pxa25x_map_io,
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa25x_init_irq,
.handle_irq = pxa25x_handle_irq,
.init_machine = corgi_init,
......@@ -753,6 +755,7 @@ MACHINE_END
MACHINE_START(HUSKY, "SHARP Husky")
.fixup = fixup_corgi,
.map_io = pxa25x_map_io,
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa25x_init_irq,
.handle_irq = pxa25x_handle_irq,
.init_machine = corgi_init,
......
......@@ -274,6 +274,7 @@ static void __init csb726_init(void)
MACHINE_START(CSB726, "Cogent CSB726")
.atag_offset = 0x100,
.map_io = pxa27x_map_io,
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa27x_init_irq,
.handle_irq = pxa27x_handle_irq,
.init_machine = csb726_init,
......
......@@ -12,6 +12,7 @@
#include <mach/pxafb.h>
#include <mach/mmc.h>
#include <mach/irda.h>
#include <mach/irqs.h>
#include <mach/ohci.h>
#include <plat/pxa27x_keypad.h>
#include <mach/camera.h>
......
......@@ -1301,6 +1301,7 @@ static void __init em_x270_init(void)
MACHINE_START(EM_X270, "Compulab EM-X270")
.atag_offset = 0x100,
.map_io = pxa27x_map_io,
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa27x_init_irq,
.handle_irq = pxa27x_handle_irq,
.timer = &pxa_timer,
......@@ -1311,6 +1312,7 @@ MACHINE_END
MACHINE_START(EXEDA, "Compulab eXeda")
.atag_offset = 0x100,
.map_io = pxa27x_map_io,
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa27x_init_irq,
.handle_irq = pxa27x_handle_irq,
.timer = &pxa_timer,
......
......@@ -235,6 +235,7 @@ static void __init gumstix_init(void)
MACHINE_START(GUMSTIX, "Gumstix")
.atag_offset = 0x100, /* match u-boot bi_boot_params */
.map_io = pxa25x_map_io,
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa25x_init_irq,
.handle_irq = pxa25x_handle_irq,
.timer = &pxa_timer,
......
......@@ -205,6 +205,7 @@ static void __init h5000_init(void)
MACHINE_START(H5400, "HP iPAQ H5000")
.atag_offset = 0x100,
.map_io = pxa25x_map_io,
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa25x_init_irq,
.handle_irq = pxa25x_handle_irq,
.timer = &pxa_timer,
......
......@@ -160,6 +160,7 @@ static void __init himalaya_init(void)
MACHINE_START(HIMALAYA, "HTC Himalaya")
.atag_offset = 0x100,
.map_io = pxa25x_map_io,
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa25x_init_irq,
.handle_irq = pxa25x_handle_irq,
.init_machine = himalaya_init,
......
......@@ -193,6 +193,7 @@ static void __init icontrol_init(void)
MACHINE_START(ICONTROL, "iControl/SafeTcam boards using Embedian MXM-8x10 CoM")
.atag_offset = 0x100,
.map_io = pxa3xx_map_io,
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa3xx_init_irq,
.handle_irq = pxa3xx_handle_irq,
.timer = &pxa_timer,
......
......@@ -195,6 +195,7 @@ static void __init idp_map_io(void)
MACHINE_START(PXA_IDP, "Vibren PXA255 IDP")
/* Maintainer: Vibren Technologies */
.map_io = idp_map_io,
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa25x_init_irq,
.handle_irq = pxa25x_handle_irq,
.timer = &pxa_timer,
......
......@@ -100,7 +100,7 @@
*/
#define IRQ_BOARD_START (PXA_GPIO_IRQ_BASE + PXA_NR_BUILTIN_GPIO)
#define NR_IRQS (IRQ_BOARD_START)
#define PXA_NR_IRQS (IRQ_BOARD_START)
#ifndef __ASSEMBLY__
struct irq_data;
......
......@@ -13,6 +13,8 @@
#ifndef ASM_ARCH_MAINSTONE_H
#define ASM_ARCH_MAINSTONE_H
#include <mach/irqs.h>
#define MST_ETH_PHYS PXA_CS4_PHYS
#define MST_FPGA_PHYS PXA_CS2_PHYS
......
......@@ -758,6 +758,7 @@ MACHINE_START(MIOA701, "MIO A701")
.atag_offset = 0x100,
.restart_mode = 's',
.map_io = &pxa27x_map_io,
.nr_irqs = PXA_NR_IRQS,
.init_irq = &pxa27x_init_irq,
.handle_irq = &pxa27x_handle_irq,
.init_machine = mioa701_machine_init,
......
......@@ -95,6 +95,7 @@ MACHINE_START(NEC_MP900, "MobilePro900/C")
.atag_offset = 0x220100,
.timer = &pxa_timer,
.map_io = pxa25x_map_io,
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa25x_init_irq,
.handle_irq = pxa25x_handle_irq,
.init_machine = mp900c_init,
......
......@@ -344,6 +344,7 @@ static void __init palmld_init(void)
MACHINE_START(PALMLD, "Palm LifeDrive")
.atag_offset = 0x100,
.map_io = palmld_map_io,
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa27x_init_irq,
.handle_irq = pxa27x_handle_irq,
.timer = &pxa_timer,
......
......@@ -205,6 +205,7 @@ MACHINE_START(PALMT5, "Palm Tungsten|T5")
.atag_offset = 0x100,
.map_io = pxa27x_map_io,
.reserve = palmt5_reserve,
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa27x_init_irq,
.handle_irq = pxa27x_handle_irq,
.timer = &pxa_timer,
......
......@@ -539,6 +539,7 @@ static void __init palmtc_init(void)
MACHINE_START(PALMTC, "Palm Tungsten|C")
.atag_offset = 0x100,
.map_io = pxa25x_map_io,
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa25x_init_irq,
.handle_irq = pxa25x_handle_irq,
.timer = &pxa_timer,
......
......@@ -358,6 +358,7 @@ static void __init palmte2_init(void)
MACHINE_START(PALMTE2, "Palm Tungsten|E2")
.atag_offset = 0x100,
.map_io = pxa25x_map_io,
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa25x_init_irq,
.handle_irq = pxa25x_handle_irq,
.timer = &pxa_timer,
......
......@@ -448,6 +448,7 @@ MACHINE_START(TREO680, "Palm Treo 680")
.atag_offset = 0x100,
.map_io = pxa27x_map_io,
.reserve = treo_reserve,
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa27x_init_irq,
.handle_irq = pxa27x_handle_irq,
.timer = &pxa_timer,
......@@ -461,6 +462,7 @@ MACHINE_START(CENTRO, "Palm Centro 685")
.atag_offset = 0x100,
.map_io = pxa27x_map_io,
.reserve = treo_reserve,
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa27x_init_irq,
.handle_irq = pxa27x_handle_irq,
.timer = &pxa_timer,
......
......@@ -366,6 +366,7 @@ static void __init palmtx_init(void)
MACHINE_START(PALMTX, "Palm T|X")
.atag_offset = 0x100,
.map_io = palmtx_map_io,
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa27x_init_irq,
.handle_irq = pxa27x_handle_irq,
.timer = &pxa_timer,
......
......@@ -401,6 +401,7 @@ static void __init palmz72_init(void)
MACHINE_START(PALMZ72, "Palm Zire72")
.atag_offset = 0x100,
.map_io = pxa27x_map_io,
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa27x_init_irq,
.handle_irq = pxa27x_handle_irq,
.timer = &pxa_timer,
......
......@@ -31,6 +31,7 @@
#include <mach/pm.h>
#include <mach/dma.h>
#include <mach/smemc.h>
#include <mach/irqs.h>
#include "generic.h"
#include "devices.h"
......
......@@ -1090,6 +1090,7 @@ MACHINE_START(RAUMFELD_RC, "Raumfeld Controller")
.atag_offset = 0x100,
.init_machine = raumfeld_controller_init,
.map_io = pxa3xx_map_io,
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa3xx_init_irq,
.handle_irq = pxa3xx_handle_irq,
.timer = &pxa_timer,
......@@ -1102,6 +1103,7 @@ MACHINE_START(RAUMFELD_CONNECTOR, "Raumfeld Connector")
.atag_offset = 0x100,
.init_machine = raumfeld_connector_init,
.map_io = pxa3xx_map_io,
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa3xx_init_irq,
.handle_irq = pxa3xx_handle_irq,
.timer = &pxa_timer,
......@@ -1114,6 +1116,7 @@ MACHINE_START(RAUMFELD_SPEAKER, "Raumfeld Speaker")
.atag_offset = 0x100,
.init_machine = raumfeld_speaker_init,
.map_io = pxa3xx_map_io,
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa3xx_init_irq,
.handle_irq = pxa3xx_handle_irq,
.timer = &pxa_timer,
......
......@@ -598,6 +598,7 @@ MACHINE_START(SAAR, "PXA930 Handheld Platform (aka SAAR)")
/* Maintainer: Eric Miao <eric.miao@marvell.com> */
.atag_offset = 0x100,
.map_io = pxa3xx_map_io,
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa3xx_init_irq,
.handle_irq = pxa3xx_handle_irq,
.timer = &pxa_timer,
......
......@@ -984,6 +984,7 @@ MACHINE_START(SPITZ, "SHARP Spitz")
.restart_mode = 'g',
.fixup = spitz_fixup,
.map_io = pxa27x_map_io,
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa27x_init_irq,
.handle_irq = pxa27x_handle_irq,
.init_machine = spitz_init,
......@@ -997,6 +998,7 @@ MACHINE_START(BORZOI, "SHARP Borzoi")
.restart_mode = 'g',
.fixup = spitz_fixup,
.map_io = pxa27x_map_io,
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa27x_init_irq,
.handle_irq = pxa27x_handle_irq,
.init_machine = spitz_init,
......@@ -1010,6 +1012,7 @@ MACHINE_START(AKITA, "SHARP Akita")
.restart_mode = 'g',
.fixup = spitz_fixup,
.map_io = pxa27x_map_io,
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa27x_init_irq,
.handle_irq = pxa27x_handle_irq,
.init_machine = spitz_init,
......
......@@ -1006,6 +1006,7 @@ static void __init stargate2_init(void)
#ifdef CONFIG_MACH_INTELMOTE2
MACHINE_START(INTELMOTE2, "IMOTE 2")
.map_io = pxa27x_map_io,
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa27x_init_irq,
.handle_irq = pxa27x_handle_irq,
.timer = &pxa_timer,
......
......@@ -491,6 +491,7 @@ MACHINE_START(TAVOREVB, "PXA930 Evaluation Board (aka TavorEVB)")
/* Maintainer: Eric Miao <eric.miao@marvell.com> */
.atag_offset = 0x100,
.map_io = pxa3xx_map_io,
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa3xx_init_irq,
.handle_irq = pxa3xx_handle_irq,
.timer = &pxa_timer,
......
......@@ -22,6 +22,7 @@
#include <asm/mach/time.h>
#include <asm/sched_clock.h>
#include <mach/regs-ost.h>
#include <mach/irqs.h>
/*
* This is PXA's sched_clock implementation. This has a resolution
......
......@@ -558,6 +558,7 @@ MACHINE_START(TRIZEPS4, "Keith und Koep Trizeps IV module")
.atag_offset = 0x100,
.init_machine = trizeps4_init,
.map_io = trizeps4_map_io,
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa27x_init_irq,
.handle_irq = pxa27x_handle_irq,
.timer = &pxa_timer,
......@@ -569,6 +570,7 @@ MACHINE_START(TRIZEPS4WL, "Keith und Koep Trizeps IV-WL module")
.atag_offset = 0x100,
.init_machine = trizeps4_init,
.map_io = trizeps4_map_io,
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa27x_init_irq,
.handle_irq = pxa27x_handle_irq,
.timer = &pxa_timer,
......
......@@ -995,6 +995,7 @@ MACHINE_START(VIPER, "Arcom/Eurotech VIPER SBC")
/* Maintainer: Marc Zyngier <maz@misterjones.org> */
.atag_offset = 0x100,
.map_io = viper_map_io,
.nr_irqs = PXA_NR_IRQS,
.init_irq = viper_init_irq,
.handle_irq = pxa25x_handle_irq,
.timer = &pxa_timer,
......
......@@ -718,6 +718,7 @@ static void __init vpac270_init(void)
MACHINE_START(VPAC270, "Voipac PXA270")
.atag_offset = 0x100,
.map_io = pxa27x_map_io,
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa27x_init_irq,
.handle_irq = pxa27x_handle_irq,
.timer = &pxa_timer,
......
......@@ -182,6 +182,7 @@ MACHINE_START(XCEP, "Iskratel XCEP")
.atag_offset = 0x100,
.init_machine = xcep_init,
.map_io = pxa25x_map_io,
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa25x_init_irq,
.handle_irq = pxa25x_handle_irq,
.timer = &pxa_timer,
......
......@@ -721,6 +721,7 @@ static void __init z2_init(void)
MACHINE_START(ZIPIT2, "Zipit Z2")
.atag_offset = 0x100,
.map_io = pxa27x_map_io,
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa27x_init_irq,
.handle_irq = pxa27x_handle_irq,
.timer = &pxa_timer,
......
......@@ -100,6 +100,10 @@ config MACH_MARZEN
comment "SH-Mobile System Configuration"
config CPU_HAS_INTEVT
bool
default y
menu "Memory configuration"
config MEMORY_START
......
......@@ -43,6 +43,7 @@
#include <video/sh_mipi_dsi.h>
#include <sound/sh_fsi.h>
#include <mach/hardware.h>
#include <mach/irqs.h>
#include <mach/sh73a0.h>
#include <mach/common.h>
#include <asm/mach-types.h>
......
......@@ -35,6 +35,7 @@
#include <asm/mach/time.h>
#include <asm/hardware/cache-l2x0.h>
#include <mach/r8a7740.h>
#include <mach/irqs.h>
#include <video/sh_mobile_lcdc.h>
/*
......
......@@ -33,6 +33,7 @@
#include <linux/input.h>
#include <linux/input/sh_keysc.h>
#include <linux/dma-mapping.h>
#include <mach/irqs.h>
#include <mach/sh7367.h>
#include <mach/common.h>
#include <asm/mach-types.h>
......
......@@ -34,6 +34,7 @@
#include <linux/mmc/sh_mobile_sdhi.h>
#include <linux/gpio.h>
#include <linux/dma-mapping.h>
#include <mach/irqs.h>
#include <mach/sh7377.h>
#include <mach/common.h>
#include <asm/mach-types.h>
......
......@@ -39,6 +39,7 @@
#include <linux/mfd/tmio.h>
#include <linux/mmc/sh_mobile_sdhi.h>
#include <mach/hardware.h>
#include <mach/irqs.h>
#include <mach/sh73a0.h>
#include <mach/common.h>
#include <asm/mach-types.h>
......
......@@ -54,6 +54,7 @@
#include <sound/sh_fsi.h>
#include <mach/common.h>
#include <mach/irqs.h>
#include <mach/sh7372.h>
#include <asm/mach/arch.h>
......
......@@ -31,6 +31,7 @@
#include <mach/hardware.h>
#include <mach/r8a7779.h>
#include <mach/common.h>
#include <mach/irqs.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/hardware/gic.h>
......
#ifndef __ASM_MACH_IRQS_H
#define __ASM_MACH_IRQS_H
#define NR_IRQS 1024
#include <linux/sh_intc.h>
/* GIC */
#define gic_spi(nr) ((nr) + 32)
/* INTCA */
#define evt2irq(evt) (((evt) >> 5) - 16)
#define irq2evt(irq) (((irq) + 16) << 5)
/* INTCS */
#define INTCS_VECT_BASE 0x2200
#define INTCS_VECT(n, vect) INTC_VECT((n), INTCS_VECT_BASE + (vect))
......
......@@ -25,6 +25,7 @@
#include <linux/io.h>
#include <linux/sh_intc.h>
#include <mach/intc.h>
#include <mach/irqs.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
......
......@@ -23,6 +23,7 @@
#include <linux/io.h>
#include <linux/sh_intc.h>
#include <mach/intc.h>
#include <mach/irqs.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
......
......@@ -23,6 +23,7 @@
#include <linux/io.h>
#include <linux/sh_intc.h>
#include <mach/intc.h>
#include <mach/irqs.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
......
......@@ -23,6 +23,7 @@
#include <linux/io.h>
#include <linux/sh_intc.h>
#include <mach/intc.h>
#include <mach/irqs.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
......
......@@ -24,6 +24,7 @@
#include <linux/io.h>
#include <linux/sh_intc.h>
#include <mach/intc.h>
#include <mach/irqs.h>
#include <mach/sh73a0.h>
#include <asm/hardware/gic.h>
#include <asm/mach-types.h>
......
......@@ -26,6 +26,7 @@
#include <linux/sh_timer.h>
#include <mach/r8a7740.h>
#include <mach/common.h>
#include <mach/irqs.h>
#include <asm/mach-types.h>
#include <asm/mach/map.h>
#include <asm/mach/arch.h>
......
......@@ -29,6 +29,7 @@
#include <linux/sh_intc.h>
#include <linux/sh_timer.h>
#include <mach/hardware.h>
#include <mach/irqs.h>
#include <mach/r8a7779.h>
#include <mach/common.h>
#include <asm/mach-types.h>
......
......@@ -30,6 +30,7 @@
#include <linux/sh_timer.h>
#include <mach/hardware.h>
#include <mach/common.h>
#include <mach/irqs.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
......
......@@ -33,6 +33,7 @@
#include <linux/pm_domain.h>
#include <linux/dma-mapping.h>
#include <mach/hardware.h>
#include <mach/irqs.h>
#include <mach/sh7372.h>
#include <mach/common.h>
#include <asm/mach/map.h>
......
......@@ -32,6 +32,7 @@
#include <mach/hardware.h>
#include <mach/common.h>
#include <asm/mach/map.h>
#include <mach/irqs.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/time.h>
......
......@@ -31,6 +31,7 @@
#include <linux/sh_intc.h>
#include <linux/sh_timer.h>
#include <mach/hardware.h>
#include <mach/irqs.h>
#include <mach/sh73a0.h>
#include <mach/common.h>
#include <asm/mach-types.h>
......
......@@ -20,7 +20,6 @@
#ifndef __ASM_ARM_ARCH_IO_H
#define __ASM_ARM_ARCH_IO_H
#define __io(a) __typesafe_io(a)
#define __mem_pci(a) (a)
#endif
......@@ -30,13 +30,13 @@
static void __iomem *l2x0_base;
static DEFINE_RAW_SPINLOCK(l2x0_lock);
static uint32_t l2x0_way_mask; /* Bitmask of active ways */
static uint32_t l2x0_size;
static u32 l2x0_way_mask; /* Bitmask of active ways */
static u32 l2x0_size;
struct l2x0_regs l2x0_saved_regs;
struct l2x0_of_data {
void (*setup)(const struct device_node *, __u32 *, __u32 *);
void (*setup)(const struct device_node *, u32 *, u32 *);
void (*save)(void);
void (*resume)(void);
};
......@@ -288,7 +288,7 @@ static void l2x0_disable(void)
raw_spin_unlock_irqrestore(&l2x0_lock, flags);
}
static void l2x0_unlock(__u32 cache_id)
static void l2x0_unlock(u32 cache_id)
{
int lockregs;
int i;
......@@ -307,11 +307,11 @@ static void l2x0_unlock(__u32 cache_id)
}
}
void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask)
void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask)
{
__u32 aux;
__u32 cache_id;
__u32 way_size = 0;
u32 aux;
u32 cache_id;
u32 way_size = 0;
int ways;
const char *type;
......@@ -388,7 +388,7 @@ void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask)
#ifdef CONFIG_OF
static void __init l2x0_of_setup(const struct device_node *np,
__u32 *aux_val, __u32 *aux_mask)
u32 *aux_val, u32 *aux_mask)
{
u32 data[2] = { 0, 0 };
u32 tag = 0;
......@@ -422,7 +422,7 @@ static void __init l2x0_of_setup(const struct device_node *np,
}
static void __init pl310_of_setup(const struct device_node *np,
__u32 *aux_val, __u32 *aux_mask)
u32 *aux_val, u32 *aux_mask)
{
u32 data[3] = { 0, 0, 0 };
u32 tag[3] = { 0, 0, 0 };
......@@ -548,7 +548,7 @@ static const struct of_device_id l2x0_ids[] __initconst = {
{}
};
int __init l2x0_of_init(__u32 aux_val, __u32 aux_mask)
int __init l2x0_of_init(u32 aux_val, u32 aux_mask)
{
struct device_node *np;
struct l2x0_of_data *data;
......
......@@ -23,10 +23,6 @@
#include "mm.h"
/*
* 0xffff8000 to 0xffffffff is reserved for any ARM architecture
* specific hacks for copying pages efficiently.
*/
#define minicache_pgprot __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | \
L_PTE_MT_MINICACHE)
......@@ -78,10 +74,9 @@ void v4_mc_copy_user_highpage(struct page *to, struct page *from,
raw_spin_lock(&minicache_lock);
set_pte_ext(TOP_PTE(0xffff8000), pfn_pte(page_to_pfn(from), minicache_pgprot), 0);
flush_tlb_kernel_page(0xffff8000);
set_top_pte(COPYPAGE_MINICACHE, mk_pte(from, minicache_pgprot));
mc_copy_user_page((void *)0xffff8000, kto);
mc_copy_user_page((void *)COPYPAGE_MINICACHE, kto);
raw_spin_unlock(&minicache_lock);
......
......@@ -24,9 +24,6 @@
#error FIX ME
#endif
#define from_address (0xffff8000)
#define to_address (0xffffc000)
static DEFINE_RAW_SPINLOCK(v6_lock);
/*
......@@ -90,14 +87,11 @@ static void v6_copy_user_highpage_aliasing(struct page *to,
*/
raw_spin_lock(&v6_lock);
set_pte_ext(TOP_PTE(from_address) + offset, pfn_pte(page_to_pfn(from), PAGE_KERNEL), 0);
set_pte_ext(TOP_PTE(to_address) + offset, pfn_pte(page_to_pfn(to), PAGE_KERNEL), 0);
kfrom = from_address + (offset << PAGE_SHIFT);
kto = to_address + (offset << PAGE_SHIFT);
kfrom = COPYPAGE_V6_FROM + (offset << PAGE_SHIFT);
kto = COPYPAGE_V6_TO + (offset << PAGE_SHIFT);
flush_tlb_kernel_page(kfrom);
flush_tlb_kernel_page(kto);
set_top_pte(kfrom, mk_pte(from, PAGE_KERNEL));
set_top_pte(kto, mk_pte(to, PAGE_KERNEL));
copy_page((void *)kto, (void *)kfrom);
......@@ -111,8 +105,7 @@ static void v6_copy_user_highpage_aliasing(struct page *to,
*/
static void v6_clear_user_highpage_aliasing(struct page *page, unsigned long vaddr)
{
unsigned int offset = CACHE_COLOUR(vaddr);
unsigned long to = to_address + (offset << PAGE_SHIFT);
unsigned long to = COPYPAGE_V6_TO + (CACHE_COLOUR(vaddr) << PAGE_SHIFT);
/* FIXME: not highmem safe */
discard_old_kernel_data(page_address(page));
......@@ -123,8 +116,7 @@ static void v6_clear_user_highpage_aliasing(struct page *page, unsigned long vad
*/
raw_spin_lock(&v6_lock);
set_pte_ext(TOP_PTE(to_address) + offset, pfn_pte(page_to_pfn(page), PAGE_KERNEL), 0);
flush_tlb_kernel_page(to);
set_top_pte(to, mk_pte(page, PAGE_KERNEL));
clear_page((void *)to);
raw_spin_unlock(&v6_lock);
......
......@@ -23,12 +23,6 @@
#include "mm.h"
/*
* 0xffff8000 to 0xffffffff is reserved for any ARM architecture
* specific hacks for copying pages efficiently.
*/
#define COPYPAGE_MINICACHE 0xffff8000
#define minicache_pgprot __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | \
L_PTE_MT_MINICACHE)
......@@ -100,8 +94,7 @@ void xscale_mc_copy_user_highpage(struct page *to, struct page *from,
raw_spin_lock(&minicache_lock);
set_pte_ext(TOP_PTE(COPYPAGE_MINICACHE), pfn_pte(page_to_pfn(from), minicache_pgprot), 0);
flush_tlb_kernel_page(COPYPAGE_MINICACHE);
set_top_pte(COPYPAGE_MINICACHE, mk_pte(from, minicache_pgprot));
mc_copy_user_page((void *)COPYPAGE_MINICACHE, kto);
......
......@@ -214,7 +214,8 @@ static int __init consistent_init(void)
core_initcall(consistent_init);
static void *
__dma_alloc_remap(struct page *page, size_t size, gfp_t gfp, pgprot_t prot)
__dma_alloc_remap(struct page *page, size_t size, gfp_t gfp, pgprot_t prot,
const void *caller)
{
struct arm_vmregion *c;
size_t align;
......@@ -241,7 +242,7 @@ __dma_alloc_remap(struct page *page, size_t size, gfp_t gfp, pgprot_t prot)
* Allocate a virtual address in the consistent mapping region.
*/
c = arm_vmregion_alloc(&consistent_head, align, size,
gfp & ~(__GFP_DMA | __GFP_HIGHMEM));
gfp & ~(__GFP_DMA | __GFP_HIGHMEM), caller);
if (c) {
pte_t *pte;
int idx = CONSISTENT_PTE_INDEX(c->vm_start);
......@@ -320,14 +321,14 @@ static void __dma_free_remap(void *cpu_addr, size_t size)
#else /* !CONFIG_MMU */
#define __dma_alloc_remap(page, size, gfp, prot) page_address(page)
#define __dma_alloc_remap(page, size, gfp, prot, c) page_address(page)
#define __dma_free_remap(addr, size) do { } while (0)
#endif /* CONFIG_MMU */
static void *
__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp,
pgprot_t prot)
pgprot_t prot, const void *caller)
{
struct page *page;
void *addr;
......@@ -349,7 +350,7 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp,
return NULL;
if (!arch_is_coherent())
addr = __dma_alloc_remap(page, size, gfp, prot);
addr = __dma_alloc_remap(page, size, gfp, prot, caller);
else
addr = page_address(page);
......@@ -374,7 +375,8 @@ dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gf
return memory;
return __dma_alloc(dev, size, handle, gfp,
pgprot_dmacoherent(pgprot_kernel));
pgprot_dmacoherent(pgprot_kernel),
__builtin_return_address(0));
}
EXPORT_SYMBOL(dma_alloc_coherent);
......@@ -386,7 +388,8 @@ void *
dma_alloc_writecombine(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp)
{
return __dma_alloc(dev, size, handle, gfp,
pgprot_writecombine(pgprot_kernel));
pgprot_writecombine(pgprot_kernel),
__builtin_return_address(0));
}
EXPORT_SYMBOL(dma_alloc_writecombine);
......@@ -723,6 +726,9 @@ EXPORT_SYMBOL(dma_set_mask);
static int __init dma_debug_do_init(void)
{
#ifdef CONFIG_MMU
arm_vmregion_create_proc("dma-mappings", &consistent_head);
#endif
dma_debug_init(PREALLOC_DMA_DEBUG_ENTRIES);
return 0;
}
......
......@@ -165,7 +165,8 @@ __do_user_fault(struct task_struct *tsk, unsigned long addr,
struct siginfo si;
#ifdef CONFIG_DEBUG_USER
if (user_debug & UDBG_SEGV) {
if (((user_debug & UDBG_SEGV) && (sig == SIGSEGV)) ||
((user_debug & UDBG_BUS) && (sig == SIGBUS))) {
printk(KERN_DEBUG "%s: unhandled page fault (%d) at 0x%08lx, code 0x%03x\n",
tsk->comm, sig, addr, fsr);
show_pte(tsk->mm, addr);
......
......@@ -22,15 +22,12 @@
#ifdef CONFIG_CPU_CACHE_VIPT
#define ALIAS_FLUSH_START 0xffff4000
static void flush_pfn_alias(unsigned long pfn, unsigned long vaddr)
{
unsigned long to = ALIAS_FLUSH_START + (CACHE_COLOUR(vaddr) << PAGE_SHIFT);
unsigned long to = FLUSH_ALIAS_START + (CACHE_COLOUR(vaddr) << PAGE_SHIFT);
const int zero = 0;
set_pte_ext(TOP_PTE(to), pfn_pte(pfn, PAGE_KERNEL), 0);
flush_tlb_kernel_page(to);
set_top_pte(to, pfn_pte(pfn, PAGE_KERNEL));
asm( "mcrr p15, 0, %1, %0, c14\n"
" mcr p15, 0, %2, c7, c10, 4"
......@@ -41,13 +38,12 @@ static void flush_pfn_alias(unsigned long pfn, unsigned long vaddr)
static void flush_icache_alias(unsigned long pfn, unsigned long vaddr, unsigned long len)
{
unsigned long colour = CACHE_COLOUR(vaddr);
unsigned long va = FLUSH_ALIAS_START + (CACHE_COLOUR(vaddr) << PAGE_SHIFT);
unsigned long offset = vaddr & (PAGE_SIZE - 1);
unsigned long to;
set_pte_ext(TOP_PTE(ALIAS_FLUSH_START) + colour, pfn_pte(pfn, PAGE_KERNEL), 0);
to = ALIAS_FLUSH_START + (colour << PAGE_SHIFT) + offset;
flush_tlb_kernel_page(to);
set_top_pte(va, pfn_pte(pfn, PAGE_KERNEL));
to = va + offset;
flush_icache_range(to, to + len);
}
......
......@@ -69,15 +69,14 @@ void *kmap_atomic(struct page *page)
* With debugging enabled, kunmap_atomic forces that entry to 0.
* Make sure it was indeed properly unmapped.
*/
BUG_ON(!pte_none(*(TOP_PTE(vaddr))));
BUG_ON(!pte_none(get_top_pte(vaddr)));
#endif
set_pte_ext(TOP_PTE(vaddr), mk_pte(page, kmap_prot), 0);
/*
* When debugging is off, kunmap_atomic leaves the previous mapping
* in place, so this TLB flush ensures the TLB is updated with the
* new mapping.
* in place, so the contained TLB flush ensures the TLB is updated
* with the new mapping.
*/
local_flush_tlb_kernel_page(vaddr);
set_top_pte(vaddr, mk_pte(page, kmap_prot));
return (void *)vaddr;
}
......@@ -96,8 +95,7 @@ void __kunmap_atomic(void *kvaddr)
__cpuc_flush_dcache_area((void *)vaddr, PAGE_SIZE);
#ifdef CONFIG_DEBUG_HIGHMEM
BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx));
set_pte_ext(TOP_PTE(vaddr), __pte(0), 0);
local_flush_tlb_kernel_page(vaddr);
set_top_pte(vaddr, __pte(0));
#else
(void) idx; /* to kill a warning */
#endif
......@@ -121,10 +119,9 @@ void *kmap_atomic_pfn(unsigned long pfn)
idx = type + KM_TYPE_NR * smp_processor_id();
vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
#ifdef CONFIG_DEBUG_HIGHMEM
BUG_ON(!pte_none(*(TOP_PTE(vaddr))));
BUG_ON(!pte_none(get_top_pte(vaddr)));
#endif
set_pte_ext(TOP_PTE(vaddr), pfn_pte(pfn, kmap_prot), 0);
local_flush_tlb_kernel_page(vaddr);
set_top_pte(vaddr, pfn_pte(pfn, kmap_prot));
return (void *)vaddr;
}
......@@ -132,11 +129,9 @@ void *kmap_atomic_pfn(unsigned long pfn)
struct page *kmap_atomic_to_page(const void *ptr)
{
unsigned long vaddr = (unsigned long)ptr;
pte_t *pte;
if (vaddr < FIXADDR_START)
return virt_to_page(ptr);
pte = TOP_PTE(vaddr);
return pte_page(*pte);
return pte_page(get_top_pte(vaddr));
}
......@@ -658,7 +658,9 @@ void __init mem_init(void)
#ifdef CONFIG_HIGHMEM
" pkmap : 0x%08lx - 0x%08lx (%4ld MB)\n"
#endif
#ifdef CONFIG_MODULES
" modules : 0x%08lx - 0x%08lx (%4ld MB)\n"
#endif
" .text : 0x%p" " - 0x%p" " (%4d kB)\n"
" .init : 0x%p" " - 0x%p" " (%4d kB)\n"
" .data : 0x%p" " - 0x%p" " (%4d kB)\n"
......@@ -677,7 +679,9 @@ void __init mem_init(void)
MLM(PKMAP_BASE, (PKMAP_BASE) + (LAST_PKMAP) *
(PAGE_SIZE)),
#endif
#ifdef CONFIG_MODULES
MLM(MODULES_VADDR, MODULES_END),
#endif
MLK_ROUNDUP(_text, _etext),
MLK_ROUNDUP(__init_begin, __init_end),
......
......@@ -3,7 +3,31 @@
/* the upper-most page table pointer */
extern pmd_t *top_pmd;
#define TOP_PTE(x) pte_offset_kernel(top_pmd, x)
/*
* 0xffff8000 to 0xffffffff is reserved for any ARM architecture
* specific hacks for copying pages efficiently, while 0xffff4000
* is reserved for VIPT aliasing flushing by generic code.
*
* Note that we don't allow VIPT aliasing caches with SMP.
*/
#define COPYPAGE_MINICACHE 0xffff8000
#define COPYPAGE_V6_FROM 0xffff8000
#define COPYPAGE_V6_TO 0xffffc000
/* PFN alias flushing, for VIPT caches */
#define FLUSH_ALIAS_START 0xffff4000
static inline void set_top_pte(unsigned long va, pte_t pte)
{
pte_t *ptep = pte_offset_kernel(top_pmd, va);
set_pte_ext(ptep, pte, 0);
local_flush_tlb_kernel_page(va);
}
static inline pte_t get_top_pte(unsigned long va)
{
pte_t *ptep = pte_offset_kernel(top_pmd, va);
return *ptep;
}
static inline pmd_t *pmd_off_k(unsigned long virt)
{
......
......@@ -999,11 +999,14 @@ static void __init devicemaps_init(struct machine_desc *mdesc)
{
struct map_desc map;
unsigned long addr;
void *vectors;
/*
* Allocate the vector page early.
*/
vectors_page = early_alloc(PAGE_SIZE);
vectors = early_alloc(PAGE_SIZE);
early_trap_init(vectors);
for (addr = VMALLOC_START; addr; addr += PMD_SIZE)
pmd_clear(pmd_off_k(addr));
......@@ -1043,7 +1046,7 @@ static void __init devicemaps_init(struct machine_desc *mdesc)
* 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_page));
map.pfn = __phys_to_pfn(virt_to_phys(vectors));
map.virtual = 0xffff0000;
map.length = PAGE_SIZE;
map.type = MT_HIGH_VECTORS;
......
#include <linux/fs.h>
#include <linux/spinlock.h>
#include <linux/list.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
#include "vmregion.h"
......@@ -36,7 +39,7 @@
struct arm_vmregion *
arm_vmregion_alloc(struct arm_vmregion_head *head, size_t align,
size_t size, gfp_t gfp)
size_t size, gfp_t gfp, const void *caller)
{
unsigned long start = head->vm_start, addr = head->vm_end;
unsigned long flags;
......@@ -52,6 +55,8 @@ arm_vmregion_alloc(struct arm_vmregion_head *head, size_t align,
if (!new)
goto out;
new->caller = caller;
spin_lock_irqsave(&head->vm_lock, flags);
addr = rounddown(addr - size, align);
......@@ -129,3 +134,72 @@ void arm_vmregion_free(struct arm_vmregion_head *head, struct arm_vmregion *c)
kfree(c);
}
#ifdef CONFIG_PROC_FS
static int arm_vmregion_show(struct seq_file *m, void *p)
{
struct arm_vmregion *c = list_entry(p, struct arm_vmregion, vm_list);
seq_printf(m, "0x%08lx-0x%08lx %7lu", c->vm_start, c->vm_end,
c->vm_end - c->vm_start);
if (c->caller)
seq_printf(m, " %pS", (void *)c->caller);
seq_putc(m, '\n');
return 0;
}
static void *arm_vmregion_start(struct seq_file *m, loff_t *pos)
{
struct arm_vmregion_head *h = m->private;
spin_lock_irq(&h->vm_lock);
return seq_list_start(&h->vm_list, *pos);
}
static void *arm_vmregion_next(struct seq_file *m, void *p, loff_t *pos)
{
struct arm_vmregion_head *h = m->private;
return seq_list_next(p, &h->vm_list, pos);
}
static void arm_vmregion_stop(struct seq_file *m, void *p)
{
struct arm_vmregion_head *h = m->private;
spin_unlock_irq(&h->vm_lock);
}
static const struct seq_operations arm_vmregion_ops = {
.start = arm_vmregion_start,
.stop = arm_vmregion_stop,
.next = arm_vmregion_next,
.show = arm_vmregion_show,
};
static int arm_vmregion_open(struct inode *inode, struct file *file)
{
struct arm_vmregion_head *h = PDE(inode)->data;
int ret = seq_open(file, &arm_vmregion_ops);
if (!ret) {
struct seq_file *m = file->private_data;
m->private = h;
}
return ret;
}
static const struct file_operations arm_vmregion_fops = {
.open = arm_vmregion_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
int arm_vmregion_create_proc(const char *path, struct arm_vmregion_head *h)
{
proc_create_data(path, S_IRUSR, NULL, &arm_vmregion_fops, h);
return 0;
}
#else
int arm_vmregion_create_proc(const char *path, struct arm_vmregion_head *h)
{
return 0;
}
#endif
......@@ -19,11 +19,14 @@ struct arm_vmregion {
unsigned long vm_end;
struct page *vm_pages;
int vm_active;
const void *caller;
};
struct arm_vmregion *arm_vmregion_alloc(struct arm_vmregion_head *, size_t, size_t, gfp_t);
struct arm_vmregion *arm_vmregion_alloc(struct arm_vmregion_head *, size_t, size_t, gfp_t, const void *);
struct arm_vmregion *arm_vmregion_find(struct arm_vmregion_head *, unsigned long);
struct arm_vmregion *arm_vmregion_find_remove(struct arm_vmregion_head *, unsigned long);
void arm_vmregion_free(struct arm_vmregion_head *, struct arm_vmregion *);
int arm_vmregion_create_proc(const char *, struct arm_vmregion_head *);
#endif
# ARM-specific networking code
obj-$(CONFIG_BPF_JIT) += bpf_jit_32.o
/*
* Just-In-Time compiler for BPF filters on 32bit ARM
*
* Copyright (c) 2011 Mircea Gherzan <mgherzan@gmail.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; version 2 of the License.
*/
#include <linux/bitops.h>
#include <linux/compiler.h>
#include <linux/errno.h>
#include <linux/filter.h>
#include <linux/moduleloader.h>
#include <linux/netdevice.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <asm/cacheflush.h>
#include <asm/hwcap.h>
#include "bpf_jit_32.h"
/*
* ABI:
*
* r0 scratch register
* r4 BPF register A
* r5 BPF register X
* r6 pointer to the skb
* r7 skb->data
* r8 skb_headlen(skb)
*/
#define r_scratch ARM_R0
/* r1-r3 are (also) used for the unaligned loads on the non-ARMv7 slowpath */
#define r_off ARM_R1
#define r_A ARM_R4
#define r_X ARM_R5
#define r_skb ARM_R6
#define r_skb_data ARM_R7
#define r_skb_hl ARM_R8
#define SCRATCH_SP_OFFSET 0
#define SCRATCH_OFF(k) (SCRATCH_SP_OFFSET + (k))
#define SEEN_MEM ((1 << BPF_MEMWORDS) - 1)
#define SEEN_MEM_WORD(k) (1 << (k))
#define SEEN_X (1 << BPF_MEMWORDS)
#define SEEN_CALL (1 << (BPF_MEMWORDS + 1))
#define SEEN_SKB (1 << (BPF_MEMWORDS + 2))
#define SEEN_DATA (1 << (BPF_MEMWORDS + 3))
#define FLAG_NEED_X_RESET (1 << 0)
struct jit_ctx {
const struct sk_filter *skf;
unsigned idx;
unsigned prologue_bytes;
int ret0_fp_idx;
u32 seen;
u32 flags;
u32 *offsets;
u32 *target;
#if __LINUX_ARM_ARCH__ < 7
u16 epilogue_bytes;
u16 imm_count;
u32 *imms;
#endif
};
int bpf_jit_enable __read_mostly;
static u64 jit_get_skb_b(struct sk_buff *skb, unsigned offset)
{
u8 ret;
int err;
err = skb_copy_bits(skb, offset, &ret, 1);
return (u64)err << 32 | ret;
}
static u64 jit_get_skb_h(struct sk_buff *skb, unsigned offset)
{
u16 ret;
int err;
err = skb_copy_bits(skb, offset, &ret, 2);
return (u64)err << 32 | ntohs(ret);
}
static u64 jit_get_skb_w(struct sk_buff *skb, unsigned offset)
{
u32 ret;
int err;
err = skb_copy_bits(skb, offset, &ret, 4);
return (u64)err << 32 | ntohl(ret);
}
/*
* Wrapper that handles both OABI and EABI and assures Thumb2 interworking
* (where the assembly routines like __aeabi_uidiv could cause problems).
*/
static u32 jit_udiv(u32 dividend, u32 divisor)
{
return dividend / divisor;
}
static inline void _emit(int cond, u32 inst, struct jit_ctx *ctx)
{
if (ctx->target != NULL)
ctx->target[ctx->idx] = inst | (cond << 28);
ctx->idx++;
}
/*
* Emit an instruction that will be executed unconditionally.
*/
static inline void emit(u32 inst, struct jit_ctx *ctx)
{
_emit(ARM_COND_AL, inst, ctx);
}
static u16 saved_regs(struct jit_ctx *ctx)
{
u16 ret = 0;
if ((ctx->skf->len > 1) ||
(ctx->skf->insns[0].code == BPF_S_RET_A))
ret |= 1 << r_A;
#ifdef CONFIG_FRAME_POINTER
ret |= (1 << ARM_FP) | (1 << ARM_IP) | (1 << ARM_LR) | (1 << ARM_PC);
#else
if (ctx->seen & SEEN_CALL)
ret |= 1 << ARM_LR;
#endif
if (ctx->seen & (SEEN_DATA | SEEN_SKB))
ret |= 1 << r_skb;
if (ctx->seen & SEEN_DATA)
ret |= (1 << r_skb_data) | (1 << r_skb_hl);
if (ctx->seen & SEEN_X)
ret |= 1 << r_X;
return ret;
}
static inline int mem_words_used(struct jit_ctx *ctx)
{
/* yes, we do waste some stack space IF there are "holes" in the set" */
return fls(ctx->seen & SEEN_MEM);
}
static inline bool is_load_to_a(u16 inst)
{
switch (inst) {
case BPF_S_LD_W_LEN:
case BPF_S_LD_W_ABS:
case BPF_S_LD_H_ABS:
case BPF_S_LD_B_ABS:
case BPF_S_ANC_CPU:
case BPF_S_ANC_IFINDEX:
case BPF_S_ANC_MARK:
case BPF_S_ANC_PROTOCOL:
case BPF_S_ANC_RXHASH:
case BPF_S_ANC_QUEUE:
return true;
default:
return false;
}
}
static void build_prologue(struct jit_ctx *ctx)
{
u16 reg_set = saved_regs(ctx);
u16 first_inst = ctx->skf->insns[0].code;
u16 off;
#ifdef CONFIG_FRAME_POINTER
emit(ARM_MOV_R(ARM_IP, ARM_SP), ctx);
emit(ARM_PUSH(reg_set), ctx);
emit(ARM_SUB_I(ARM_FP, ARM_IP, 4), ctx);
#else
if (reg_set)
emit(ARM_PUSH(reg_set), ctx);
#endif
if (ctx->seen & (SEEN_DATA | SEEN_SKB))
emit(ARM_MOV_R(r_skb, ARM_R0), ctx);
if (ctx->seen & SEEN_DATA) {
off = offsetof(struct sk_buff, data);
emit(ARM_LDR_I(r_skb_data, r_skb, off), ctx);
/* headlen = len - data_len */
off = offsetof(struct sk_buff, len);
emit(ARM_LDR_I(r_skb_hl, r_skb, off), ctx);
off = offsetof(struct sk_buff, data_len);
emit(ARM_LDR_I(r_scratch, r_skb, off), ctx);
emit(ARM_SUB_R(r_skb_hl, r_skb_hl, r_scratch), ctx);
}
if (ctx->flags & FLAG_NEED_X_RESET)
emit(ARM_MOV_I(r_X, 0), ctx);
/* do not leak kernel data to userspace */
if ((first_inst != BPF_S_RET_K) && !(is_load_to_a(first_inst)))
emit(ARM_MOV_I(r_A, 0), ctx);
/* stack space for the BPF_MEM words */
if (ctx->seen & SEEN_MEM)
emit(ARM_SUB_I(ARM_SP, ARM_SP, mem_words_used(ctx) * 4), ctx);
}
static void build_epilogue(struct jit_ctx *ctx)
{
u16 reg_set = saved_regs(ctx);
if (ctx->seen & SEEN_MEM)
emit(ARM_ADD_I(ARM_SP, ARM_SP, mem_words_used(ctx) * 4), ctx);
reg_set &= ~(1 << ARM_LR);
#ifdef CONFIG_FRAME_POINTER
/* the first instruction of the prologue was: mov ip, sp */
reg_set &= ~(1 << ARM_IP);
reg_set |= (1 << ARM_SP);
emit(ARM_LDM(ARM_SP, reg_set), ctx);
#else
if (reg_set) {
if (ctx->seen & SEEN_CALL)
reg_set |= 1 << ARM_PC;
emit(ARM_POP(reg_set), ctx);
}
if (!(ctx->seen & SEEN_CALL))
emit(ARM_BX(ARM_LR), ctx);
#endif
}
static int16_t imm8m(u32 x)
{
u32 rot;
for (rot = 0; rot < 16; rot++)
if ((x & ~ror32(0xff, 2 * rot)) == 0)
return rol32(x, 2 * rot) | (rot << 8);
return -1;
}
#if __LINUX_ARM_ARCH__ < 7
static u16 imm_offset(u32 k, struct jit_ctx *ctx)
{
unsigned i = 0, offset;
u16 imm;
/* on the "fake" run we just count them (duplicates included) */
if (ctx->target == NULL) {
ctx->imm_count++;
return 0;
}
while ((i < ctx->imm_count) && ctx->imms[i]) {
if (ctx->imms[i] == k)
break;
i++;
}
if (ctx->imms[i] == 0)
ctx->imms[i] = k;
/* constants go just after the epilogue */
offset = ctx->offsets[ctx->skf->len];
offset += ctx->prologue_bytes;
offset += ctx->epilogue_bytes;
offset += i * 4;
ctx->target[offset / 4] = k;
/* PC in ARM mode == address of the instruction + 8 */
imm = offset - (8 + ctx->idx * 4);
return imm;
}
#endif /* __LINUX_ARM_ARCH__ */
/*
* Move an immediate that's not an imm8m to a core register.
*/
static inline void emit_mov_i_no8m(int rd, u32 val, struct jit_ctx *ctx)
{
#if __LINUX_ARM_ARCH__ < 7
emit(ARM_LDR_I(rd, ARM_PC, imm_offset(val, ctx)), ctx);
#else
emit(ARM_MOVW(rd, val & 0xffff), ctx);
if (val > 0xffff)
emit(ARM_MOVT(rd, val >> 16), ctx);
#endif
}
static inline void emit_mov_i(int rd, u32 val, struct jit_ctx *ctx)
{
int imm12 = imm8m(val);
if (imm12 >= 0)
emit(ARM_MOV_I(rd, imm12), ctx);
else
emit_mov_i_no8m(rd, val, ctx);
}
#if __LINUX_ARM_ARCH__ < 6
static void emit_load_be32(u8 cond, u8 r_res, u8 r_addr, struct jit_ctx *ctx)
{
_emit(cond, ARM_LDRB_I(ARM_R3, r_addr, 1), ctx);
_emit(cond, ARM_LDRB_I(ARM_R1, r_addr, 0), ctx);
_emit(cond, ARM_LDRB_I(ARM_R2, r_addr, 3), ctx);
_emit(cond, ARM_LSL_I(ARM_R3, ARM_R3, 16), ctx);
_emit(cond, ARM_LDRB_I(ARM_R0, r_addr, 2), ctx);
_emit(cond, ARM_ORR_S(ARM_R3, ARM_R3, ARM_R1, SRTYPE_LSL, 24), ctx);
_emit(cond, ARM_ORR_R(ARM_R3, ARM_R3, ARM_R2), ctx);
_emit(cond, ARM_ORR_S(r_res, ARM_R3, ARM_R0, SRTYPE_LSL, 8), ctx);
}
static void emit_load_be16(u8 cond, u8 r_res, u8 r_addr, struct jit_ctx *ctx)
{
_emit(cond, ARM_LDRB_I(ARM_R1, r_addr, 0), ctx);
_emit(cond, ARM_LDRB_I(ARM_R2, r_addr, 1), ctx);
_emit(cond, ARM_ORR_S(r_res, ARM_R2, ARM_R1, SRTYPE_LSL, 8), ctx);
}
static inline void emit_swap16(u8 r_dst, u8 r_src, struct jit_ctx *ctx)
{
emit(ARM_LSL_R(ARM_R1, r_src, 8), ctx);
emit(ARM_ORR_S(r_dst, ARM_R1, r_src, SRTYPE_LSL, 8), ctx);
emit(ARM_LSL_I(r_dst, r_dst, 8), ctx);
emit(ARM_LSL_R(r_dst, r_dst, 8), ctx);
}
#else /* ARMv6+ */
static void emit_load_be32(u8 cond, u8 r_res, u8 r_addr, struct jit_ctx *ctx)
{
_emit(cond, ARM_LDR_I(r_res, r_addr, 0), ctx);
#ifdef __LITTLE_ENDIAN
_emit(cond, ARM_REV(r_res, r_res), ctx);
#endif
}
static void emit_load_be16(u8 cond, u8 r_res, u8 r_addr, struct jit_ctx *ctx)
{
_emit(cond, ARM_LDRH_I(r_res, r_addr, 0), ctx);
#ifdef __LITTLE_ENDIAN
_emit(cond, ARM_REV16(r_res, r_res), ctx);
#endif
}
static inline void emit_swap16(u8 r_dst __maybe_unused,
u8 r_src __maybe_unused,
struct jit_ctx *ctx __maybe_unused)
{
#ifdef __LITTLE_ENDIAN
emit(ARM_REV16(r_dst, r_src), ctx);
#endif
}
#endif /* __LINUX_ARM_ARCH__ < 6 */
/* Compute the immediate value for a PC-relative branch. */
static inline u32 b_imm(unsigned tgt, struct jit_ctx *ctx)
{
u32 imm;
if (ctx->target == NULL)
return 0;
/*
* BPF allows only forward jumps and the offset of the target is
* still the one computed during the first pass.
*/
imm = ctx->offsets[tgt] + ctx->prologue_bytes - (ctx->idx * 4 + 8);
return imm >> 2;
}
#define OP_IMM3(op, r1, r2, imm_val, ctx) \
do { \
imm12 = imm8m(imm_val); \
if (imm12 < 0) { \
emit_mov_i_no8m(r_scratch, imm_val, ctx); \
emit(op ## _R((r1), (r2), r_scratch), ctx); \
} else { \
emit(op ## _I((r1), (r2), imm12), ctx); \
} \
} while (0)
static inline void emit_err_ret(u8 cond, struct jit_ctx *ctx)
{
if (ctx->ret0_fp_idx >= 0) {
_emit(cond, ARM_B(b_imm(ctx->ret0_fp_idx, ctx)), ctx);
/* NOP to keep the size constant between passes */
emit(ARM_MOV_R(ARM_R0, ARM_R0), ctx);
} else {
_emit(cond, ARM_MOV_I(ARM_R0, 0), ctx);
_emit(cond, ARM_B(b_imm(ctx->skf->len, ctx)), ctx);
}
}
static inline void emit_blx_r(u8 tgt_reg, struct jit_ctx *ctx)
{
#if __LINUX_ARM_ARCH__ < 5
emit(ARM_MOV_R(ARM_LR, ARM_PC), ctx);
if (elf_hwcap & HWCAP_THUMB)
emit(ARM_BX(tgt_reg), ctx);
else
emit(ARM_MOV_R(ARM_PC, tgt_reg), ctx);
#else
emit(ARM_BLX_R(tgt_reg), ctx);
#endif
}
static inline void emit_udiv(u8 rd, u8 rm, u8 rn, struct jit_ctx *ctx)
{
#if __LINUX_ARM_ARCH__ == 7
if (elf_hwcap & HWCAP_IDIVA) {
emit(ARM_UDIV(rd, rm, rn), ctx);
return;
}
#endif
if (rm != ARM_R0)
emit(ARM_MOV_R(ARM_R0, rm), ctx);
if (rn != ARM_R1)
emit(ARM_MOV_R(ARM_R1, rn), ctx);
ctx->seen |= SEEN_CALL;
emit_mov_i(ARM_R3, (u32)jit_udiv, ctx);
emit_blx_r(ARM_R3, ctx);
if (rd != ARM_R0)
emit(ARM_MOV_R(rd, ARM_R0), ctx);
}
static inline void update_on_xread(struct jit_ctx *ctx)
{
if (!(ctx->seen & SEEN_X))
ctx->flags |= FLAG_NEED_X_RESET;
ctx->seen |= SEEN_X;
}
static int build_body(struct jit_ctx *ctx)
{
void *load_func[] = {jit_get_skb_b, jit_get_skb_h, jit_get_skb_w};
const struct sk_filter *prog = ctx->skf;
const struct sock_filter *inst;
unsigned i, load_order, off, condt;
int imm12;
u32 k;
for (i = 0; i < prog->len; i++) {
inst = &(prog->insns[i]);
/* K as an immediate value operand */
k = inst->k;
/* compute offsets only in the fake pass */
if (ctx->target == NULL)
ctx->offsets[i] = ctx->idx * 4;
switch (inst->code) {
case BPF_S_LD_IMM:
emit_mov_i(r_A, k, ctx);
break;
case BPF_S_LD_W_LEN:
ctx->seen |= SEEN_SKB;
BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, len) != 4);
emit(ARM_LDR_I(r_A, r_skb,
offsetof(struct sk_buff, len)), ctx);
break;
case BPF_S_LD_MEM:
/* A = scratch[k] */
ctx->seen |= SEEN_MEM_WORD(k);
emit(ARM_LDR_I(r_A, ARM_SP, SCRATCH_OFF(k)), ctx);
break;
case BPF_S_LD_W_ABS:
load_order = 2;
goto load;
case BPF_S_LD_H_ABS:
load_order = 1;
goto load;
case BPF_S_LD_B_ABS:
load_order = 0;
load:
/* the interpreter will deal with the negative K */
if ((int)k < 0)
return -ENOTSUPP;
emit_mov_i(r_off, k, ctx);
load_common:
ctx->seen |= SEEN_DATA | SEEN_CALL;
if (load_order > 0) {
emit(ARM_SUB_I(r_scratch, r_skb_hl,
1 << load_order), ctx);
emit(ARM_CMP_R(r_scratch, r_off), ctx);
condt = ARM_COND_HS;
} else {
emit(ARM_CMP_R(r_skb_hl, r_off), ctx);
condt = ARM_COND_HI;
}
_emit(condt, ARM_ADD_R(r_scratch, r_off, r_skb_data),
ctx);
if (load_order == 0)
_emit(condt, ARM_LDRB_I(r_A, r_scratch, 0),
ctx);
else if (load_order == 1)
emit_load_be16(condt, r_A, r_scratch, ctx);
else if (load_order == 2)
emit_load_be32(condt, r_A, r_scratch, ctx);
_emit(condt, ARM_B(b_imm(i + 1, ctx)), ctx);
/* the slowpath */
emit_mov_i(ARM_R3, (u32)load_func[load_order], ctx);
emit(ARM_MOV_R(ARM_R0, r_skb), ctx);
/* the offset is already in R1 */
emit_blx_r(ARM_R3, ctx);
/* check the result of skb_copy_bits */
emit(ARM_CMP_I(ARM_R1, 0), ctx);
emit_err_ret(ARM_COND_NE, ctx);
emit(ARM_MOV_R(r_A, ARM_R0), ctx);
break;
case BPF_S_LD_W_IND:
load_order = 2;
goto load_ind;
case BPF_S_LD_H_IND:
load_order = 1;
goto load_ind;
case BPF_S_LD_B_IND:
load_order = 0;
load_ind:
OP_IMM3(ARM_ADD, r_off, r_X, k, ctx);
goto load_common;
case BPF_S_LDX_IMM:
ctx->seen |= SEEN_X;
emit_mov_i(r_X, k, ctx);
break;
case BPF_S_LDX_W_LEN:
ctx->seen |= SEEN_X | SEEN_SKB;
emit(ARM_LDR_I(r_X, r_skb,
offsetof(struct sk_buff, len)), ctx);
break;
case BPF_S_LDX_MEM:
ctx->seen |= SEEN_X | SEEN_MEM_WORD(k);
emit(ARM_LDR_I(r_X, ARM_SP, SCRATCH_OFF(k)), ctx);
break;
case BPF_S_LDX_B_MSH:
/* x = ((*(frame + k)) & 0xf) << 2; */
ctx->seen |= SEEN_X | SEEN_DATA | SEEN_CALL;
/* the interpreter should deal with the negative K */
if (k < 0)
return -1;
/* offset in r1: we might have to take the slow path */
emit_mov_i(r_off, k, ctx);
emit(ARM_CMP_R(r_skb_hl, r_off), ctx);
/* load in r0: common with the slowpath */
_emit(ARM_COND_HI, ARM_LDRB_R(ARM_R0, r_skb_data,
ARM_R1), ctx);
/*
* emit_mov_i() might generate one or two instructions,
* the same holds for emit_blx_r()
*/
_emit(ARM_COND_HI, ARM_B(b_imm(i + 1, ctx) - 2), ctx);
emit(ARM_MOV_R(ARM_R0, r_skb), ctx);
/* r_off is r1 */
emit_mov_i(ARM_R3, (u32)jit_get_skb_b, ctx);
emit_blx_r(ARM_R3, ctx);
/* check the return value of skb_copy_bits */
emit(ARM_CMP_I(ARM_R1, 0), ctx);
emit_err_ret(ARM_COND_NE, ctx);
emit(ARM_AND_I(r_X, ARM_R0, 0x00f), ctx);
emit(ARM_LSL_I(r_X, r_X, 2), ctx);
break;
case BPF_S_ST:
ctx->seen |= SEEN_MEM_WORD(k);
emit(ARM_STR_I(r_A, ARM_SP, SCRATCH_OFF(k)), ctx);
break;
case BPF_S_STX:
update_on_xread(ctx);
ctx->seen |= SEEN_MEM_WORD(k);
emit(ARM_STR_I(r_X, ARM_SP, SCRATCH_OFF(k)), ctx);
break;
case BPF_S_ALU_ADD_K:
/* A += K */
OP_IMM3(ARM_ADD, r_A, r_A, k, ctx);
break;
case BPF_S_ALU_ADD_X:
update_on_xread(ctx);
emit(ARM_ADD_R(r_A, r_A, r_X), ctx);
break;
case BPF_S_ALU_SUB_K:
/* A -= K */
OP_IMM3(ARM_SUB, r_A, r_A, k, ctx);
break;
case BPF_S_ALU_SUB_X:
update_on_xread(ctx);
emit(ARM_SUB_R(r_A, r_A, r_X), ctx);
break;
case BPF_S_ALU_MUL_K:
/* A *= K */
emit_mov_i(r_scratch, k, ctx);
emit(ARM_MUL(r_A, r_A, r_scratch), ctx);
break;
case BPF_S_ALU_MUL_X:
update_on_xread(ctx);
emit(ARM_MUL(r_A, r_A, r_X), ctx);
break;
case BPF_S_ALU_DIV_K:
/* current k == reciprocal_value(userspace k) */
emit_mov_i(r_scratch, k, ctx);
/* A = top 32 bits of the product */
emit(ARM_UMULL(r_scratch, r_A, r_A, r_scratch), ctx);
break;
case BPF_S_ALU_DIV_X:
update_on_xread(ctx);
emit(ARM_CMP_I(r_X, 0), ctx);
emit_err_ret(ARM_COND_EQ, ctx);
emit_udiv(r_A, r_A, r_X, ctx);
break;
case BPF_S_ALU_OR_K:
/* A |= K */
OP_IMM3(ARM_ORR, r_A, r_A, k, ctx);
break;
case BPF_S_ALU_OR_X:
update_on_xread(ctx);
emit(ARM_ORR_R(r_A, r_A, r_X), ctx);
break;
case BPF_S_ALU_AND_K:
/* A &= K */
OP_IMM3(ARM_AND, r_A, r_A, k, ctx);
break;
case BPF_S_ALU_AND_X:
update_on_xread(ctx);
emit(ARM_AND_R(r_A, r_A, r_X), ctx);
break;
case BPF_S_ALU_LSH_K:
if (unlikely(k > 31))
return -1;
emit(ARM_LSL_I(r_A, r_A, k), ctx);
break;
case BPF_S_ALU_LSH_X:
update_on_xread(ctx);
emit(ARM_LSL_R(r_A, r_A, r_X), ctx);
break;
case BPF_S_ALU_RSH_K:
if (unlikely(k > 31))
return -1;
emit(ARM_LSR_I(r_A, r_A, k), ctx);
break;
case BPF_S_ALU_RSH_X:
update_on_xread(ctx);
emit(ARM_LSR_R(r_A, r_A, r_X), ctx);
break;
case BPF_S_ALU_NEG:
/* A = -A */
emit(ARM_RSB_I(r_A, r_A, 0), ctx);
break;
case BPF_S_JMP_JA:
/* pc += K */
emit(ARM_B(b_imm(i + k + 1, ctx)), ctx);
break;
case BPF_S_JMP_JEQ_K:
/* pc += (A == K) ? pc->jt : pc->jf */
condt = ARM_COND_EQ;
goto cmp_imm;
case BPF_S_JMP_JGT_K:
/* pc += (A > K) ? pc->jt : pc->jf */
condt = ARM_COND_HI;
goto cmp_imm;
case BPF_S_JMP_JGE_K:
/* pc += (A >= K) ? pc->jt : pc->jf */
condt = ARM_COND_HS;
cmp_imm:
imm12 = imm8m(k);
if (imm12 < 0) {
emit_mov_i_no8m(r_scratch, k, ctx);
emit(ARM_CMP_R(r_A, r_scratch), ctx);
} else {
emit(ARM_CMP_I(r_A, imm12), ctx);
}
cond_jump:
if (inst->jt)
_emit(condt, ARM_B(b_imm(i + inst->jt + 1,
ctx)), ctx);
if (inst->jf)
_emit(condt ^ 1, ARM_B(b_imm(i + inst->jf + 1,
ctx)), ctx);
break;
case BPF_S_JMP_JEQ_X:
/* pc += (A == X) ? pc->jt : pc->jf */
condt = ARM_COND_EQ;
goto cmp_x;
case BPF_S_JMP_JGT_X:
/* pc += (A > X) ? pc->jt : pc->jf */
condt = ARM_COND_HI;
goto cmp_x;
case BPF_S_JMP_JGE_X:
/* pc += (A >= X) ? pc->jt : pc->jf */
condt = ARM_COND_CS;
cmp_x:
update_on_xread(ctx);
emit(ARM_CMP_R(r_A, r_X), ctx);
goto cond_jump;
case BPF_S_JMP_JSET_K:
/* pc += (A & K) ? pc->jt : pc->jf */
condt = ARM_COND_NE;
/* not set iff all zeroes iff Z==1 iff EQ */
imm12 = imm8m(k);
if (imm12 < 0) {
emit_mov_i_no8m(r_scratch, k, ctx);
emit(ARM_TST_R(r_A, r_scratch), ctx);
} else {
emit(ARM_TST_I(r_A, imm12), ctx);
}
goto cond_jump;
case BPF_S_JMP_JSET_X:
/* pc += (A & X) ? pc->jt : pc->jf */
update_on_xread(ctx);
condt = ARM_COND_NE;
emit(ARM_TST_R(r_A, r_X), ctx);
goto cond_jump;
case BPF_S_RET_A:
emit(ARM_MOV_R(ARM_R0, r_A), ctx);
goto b_epilogue;
case BPF_S_RET_K:
if ((k == 0) && (ctx->ret0_fp_idx < 0))
ctx->ret0_fp_idx = i;
emit_mov_i(ARM_R0, k, ctx);
b_epilogue:
if (i != ctx->skf->len - 1)
emit(ARM_B(b_imm(prog->len, ctx)), ctx);
break;
case BPF_S_MISC_TAX:
/* X = A */
ctx->seen |= SEEN_X;
emit(ARM_MOV_R(r_X, r_A), ctx);
break;
case BPF_S_MISC_TXA:
/* A = X */
update_on_xread(ctx);
emit(ARM_MOV_R(r_A, r_X), ctx);
break;
case BPF_S_ANC_PROTOCOL:
/* A = ntohs(skb->protocol) */
ctx->seen |= SEEN_SKB;
BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff,
protocol) != 2);
off = offsetof(struct sk_buff, protocol);
emit(ARM_LDRH_I(r_scratch, r_skb, off), ctx);
emit_swap16(r_A, r_scratch, ctx);
break;
case BPF_S_ANC_CPU:
/* r_scratch = current_thread_info() */
OP_IMM3(ARM_BIC, r_scratch, ARM_SP, THREAD_SIZE - 1, ctx);
/* A = current_thread_info()->cpu */
BUILD_BUG_ON(FIELD_SIZEOF(struct thread_info, cpu) != 4);
off = offsetof(struct thread_info, cpu);
emit(ARM_LDR_I(r_A, r_scratch, off), ctx);
break;
case BPF_S_ANC_IFINDEX:
/* A = skb->dev->ifindex */
ctx->seen |= SEEN_SKB;
off = offsetof(struct sk_buff, dev);
emit(ARM_LDR_I(r_scratch, r_skb, off), ctx);
emit(ARM_CMP_I(r_scratch, 0), ctx);
emit_err_ret(ARM_COND_EQ, ctx);
BUILD_BUG_ON(FIELD_SIZEOF(struct net_device,
ifindex) != 4);
off = offsetof(struct net_device, ifindex);
emit(ARM_LDR_I(r_A, r_scratch, off), ctx);
break;
case BPF_S_ANC_MARK:
ctx->seen |= SEEN_SKB;
BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, mark) != 4);
off = offsetof(struct sk_buff, mark);
emit(ARM_LDR_I(r_A, r_skb, off), ctx);
break;
case BPF_S_ANC_RXHASH:
ctx->seen |= SEEN_SKB;
BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, rxhash) != 4);
off = offsetof(struct sk_buff, rxhash);
emit(ARM_LDR_I(r_A, r_skb, off), ctx);
break;
case BPF_S_ANC_QUEUE:
ctx->seen |= SEEN_SKB;
BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff,
queue_mapping) != 2);
BUILD_BUG_ON(offsetof(struct sk_buff,
queue_mapping) > 0xff);
off = offsetof(struct sk_buff, queue_mapping);
emit(ARM_LDRH_I(r_A, r_skb, off), ctx);
break;
default:
return -1;
}
}
/* compute offsets only during the first pass */
if (ctx->target == NULL)
ctx->offsets[i] = ctx->idx * 4;
return 0;
}
void bpf_jit_compile(struct sk_filter *fp)
{
struct jit_ctx ctx;
unsigned tmp_idx;
unsigned alloc_size;
if (!bpf_jit_enable)
return;
memset(&ctx, 0, sizeof(ctx));
ctx.skf = fp;
ctx.ret0_fp_idx = -1;
ctx.offsets = kzalloc(GFP_KERNEL, 4 * (ctx.skf->len + 1));
if (ctx.offsets == NULL)
return;
/* fake pass to fill in the ctx->seen */
if (unlikely(build_body(&ctx)))
goto out;
tmp_idx = ctx.idx;
build_prologue(&ctx);
ctx.prologue_bytes = (ctx.idx - tmp_idx) * 4;
#if __LINUX_ARM_ARCH__ < 7
tmp_idx = ctx.idx;
build_epilogue(&ctx);
ctx.epilogue_bytes = (ctx.idx - tmp_idx) * 4;
ctx.idx += ctx.imm_count;
if (ctx.imm_count) {
ctx.imms = kzalloc(GFP_KERNEL, 4 * ctx.imm_count);
if (ctx.imms == NULL)
goto out;
}
#else
/* there's nothing after the epilogue on ARMv7 */
build_epilogue(&ctx);
#endif
alloc_size = 4 * ctx.idx;
ctx.target = module_alloc(max(sizeof(struct work_struct),
alloc_size));
if (unlikely(ctx.target == NULL))
goto out;
ctx.idx = 0;
build_prologue(&ctx);
build_body(&ctx);
build_epilogue(&ctx);
flush_icache_range((u32)ctx.target, (u32)(ctx.target + ctx.idx));
#if __LINUX_ARM_ARCH__ < 7
if (ctx.imm_count)
kfree(ctx.imms);
#endif
if (bpf_jit_enable > 1)
print_hex_dump(KERN_INFO, "BPF JIT code: ",
DUMP_PREFIX_ADDRESS, 16, 4, ctx.target,
alloc_size, false);
fp->bpf_func = (void *)ctx.target;
out:
kfree(ctx.offsets);
return;
}
static void bpf_jit_free_worker(struct work_struct *work)
{
module_free(NULL, work);
}
void bpf_jit_free(struct sk_filter *fp)
{
struct work_struct *work;
if (fp->bpf_func != sk_run_filter) {
work = (struct work_struct *)fp->bpf_func;
INIT_WORK(work, bpf_jit_free_worker);
schedule_work(work);
}
}
/*
* Just-In-Time compiler for BPF filters on 32bit ARM
*
* Copyright (c) 2011 Mircea Gherzan <mgherzan@gmail.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; version 2 of the License.
*/
#ifndef PFILTER_OPCODES_ARM_H
#define PFILTER_OPCODES_ARM_H
#define ARM_R0 0
#define ARM_R1 1
#define ARM_R2 2
#define ARM_R3 3
#define ARM_R4 4
#define ARM_R5 5
#define ARM_R6 6
#define ARM_R7 7
#define ARM_R8 8
#define ARM_R9 9
#define ARM_R10 10
#define ARM_FP 11
#define ARM_IP 12
#define ARM_SP 13
#define ARM_LR 14
#define ARM_PC 15
#define ARM_COND_EQ 0x0
#define ARM_COND_NE 0x1
#define ARM_COND_CS 0x2
#define ARM_COND_HS ARM_COND_CS
#define ARM_COND_CC 0x3
#define ARM_COND_LO ARM_COND_CC
#define ARM_COND_MI 0x4
#define ARM_COND_PL 0x5
#define ARM_COND_VS 0x6
#define ARM_COND_VC 0x7
#define ARM_COND_HI 0x8
#define ARM_COND_LS 0x9
#define ARM_COND_GE 0xa
#define ARM_COND_LT 0xb
#define ARM_COND_GT 0xc
#define ARM_COND_LE 0xd
#define ARM_COND_AL 0xe
/* register shift types */
#define SRTYPE_LSL 0
#define SRTYPE_LSR 1
#define SRTYPE_ASR 2
#define SRTYPE_ROR 3
#define ARM_INST_ADD_R 0x00800000
#define ARM_INST_ADD_I 0x02800000
#define ARM_INST_AND_R 0x00000000
#define ARM_INST_AND_I 0x02000000
#define ARM_INST_BIC_R 0x01c00000
#define ARM_INST_BIC_I 0x03c00000
#define ARM_INST_B 0x0a000000
#define ARM_INST_BX 0x012FFF10
#define ARM_INST_BLX_R 0x012fff30
#define ARM_INST_CMP_R 0x01500000
#define ARM_INST_CMP_I 0x03500000
#define ARM_INST_LDRB_I 0x05d00000
#define ARM_INST_LDRB_R 0x07d00000
#define ARM_INST_LDRH_I 0x01d000b0
#define ARM_INST_LDR_I 0x05900000
#define ARM_INST_LDM 0x08900000
#define ARM_INST_LSL_I 0x01a00000
#define ARM_INST_LSL_R 0x01a00010
#define ARM_INST_LSR_I 0x01a00020
#define ARM_INST_LSR_R 0x01a00030
#define ARM_INST_MOV_R 0x01a00000
#define ARM_INST_MOV_I 0x03a00000
#define ARM_INST_MOVW 0x03000000
#define ARM_INST_MOVT 0x03400000
#define ARM_INST_MUL 0x00000090
#define ARM_INST_POP 0x08bd0000
#define ARM_INST_PUSH 0x092d0000
#define ARM_INST_ORR_R 0x01800000
#define ARM_INST_ORR_I 0x03800000
#define ARM_INST_REV 0x06bf0f30
#define ARM_INST_REV16 0x06bf0fb0
#define ARM_INST_RSB_I 0x02600000
#define ARM_INST_SUB_R 0x00400000
#define ARM_INST_SUB_I 0x02400000
#define ARM_INST_STR_I 0x05800000
#define ARM_INST_TST_R 0x01100000
#define ARM_INST_TST_I 0x03100000
#define ARM_INST_UDIV 0x0730f010
#define ARM_INST_UMULL 0x00800090
/* register */
#define _AL3_R(op, rd, rn, rm) ((op ## _R) | (rd) << 12 | (rn) << 16 | (rm))
/* immediate */
#define _AL3_I(op, rd, rn, imm) ((op ## _I) | (rd) << 12 | (rn) << 16 | (imm))
#define ARM_ADD_R(rd, rn, rm) _AL3_R(ARM_INST_ADD, rd, rn, rm)
#define ARM_ADD_I(rd, rn, imm) _AL3_I(ARM_INST_ADD, rd, rn, imm)
#define ARM_AND_R(rd, rn, rm) _AL3_R(ARM_INST_AND, rd, rn, rm)
#define ARM_AND_I(rd, rn, imm) _AL3_I(ARM_INST_AND, rd, rn, imm)
#define ARM_BIC_R(rd, rn, rm) _AL3_R(ARM_INST_BIC, rd, rn, rm)
#define ARM_BIC_I(rd, rn, imm) _AL3_I(ARM_INST_BIC, rd, rn, imm)
#define ARM_B(imm24) (ARM_INST_B | ((imm24) & 0xffffff))
#define ARM_BX(rm) (ARM_INST_BX | (rm))
#define ARM_BLX_R(rm) (ARM_INST_BLX_R | (rm))
#define ARM_CMP_R(rn, rm) _AL3_R(ARM_INST_CMP, 0, rn, rm)
#define ARM_CMP_I(rn, imm) _AL3_I(ARM_INST_CMP, 0, rn, imm)
#define ARM_LDR_I(rt, rn, off) (ARM_INST_LDR_I | (rt) << 12 | (rn) << 16 \
| (off))
#define ARM_LDRB_I(rt, rn, off) (ARM_INST_LDRB_I | (rt) << 12 | (rn) << 16 \
| (off))
#define ARM_LDRB_R(rt, rn, rm) (ARM_INST_LDRB_R | (rt) << 12 | (rn) << 16 \
| (rm))
#define ARM_LDRH_I(rt, rn, off) (ARM_INST_LDRH_I | (rt) << 12 | (rn) << 16 \
| (((off) & 0xf0) << 4) | ((off) & 0xf))
#define ARM_LDM(rn, regs) (ARM_INST_LDM | (rn) << 16 | (regs))
#define ARM_LSL_R(rd, rn, rm) (_AL3_R(ARM_INST_LSL, rd, 0, rn) | (rm) << 8)
#define ARM_LSL_I(rd, rn, imm) (_AL3_I(ARM_INST_LSL, rd, 0, rn) | (imm) << 7)
#define ARM_LSR_R(rd, rn, rm) (_AL3_R(ARM_INST_LSR, rd, 0, rn) | (rm) << 8)
#define ARM_LSR_I(rd, rn, imm) (_AL3_I(ARM_INST_LSR, rd, 0, rn) | (imm) << 7)
#define ARM_MOV_R(rd, rm) _AL3_R(ARM_INST_MOV, rd, 0, rm)
#define ARM_MOV_I(rd, imm) _AL3_I(ARM_INST_MOV, rd, 0, imm)
#define ARM_MOVW(rd, imm) \
(ARM_INST_MOVW | ((imm) >> 12) << 16 | (rd) << 12 | ((imm) & 0x0fff))
#define ARM_MOVT(rd, imm) \
(ARM_INST_MOVT | ((imm) >> 12) << 16 | (rd) << 12 | ((imm) & 0x0fff))
#define ARM_MUL(rd, rm, rn) (ARM_INST_MUL | (rd) << 16 | (rm) << 8 | (rn))
#define ARM_POP(regs) (ARM_INST_POP | (regs))
#define ARM_PUSH(regs) (ARM_INST_PUSH | (regs))
#define ARM_ORR_R(rd, rn, rm) _AL3_R(ARM_INST_ORR, rd, rn, rm)
#define ARM_ORR_I(rd, rn, imm) _AL3_I(ARM_INST_ORR, rd, rn, imm)
#define ARM_ORR_S(rd, rn, rm, type, rs) \
(ARM_ORR_R(rd, rn, rm) | (type) << 5 | (rs) << 7)
#define ARM_REV(rd, rm) (ARM_INST_REV | (rd) << 12 | (rm))
#define ARM_REV16(rd, rm) (ARM_INST_REV16 | (rd) << 12 | (rm))
#define ARM_RSB_I(rd, rn, imm) _AL3_I(ARM_INST_RSB, rd, rn, imm)
#define ARM_SUB_R(rd, rn, rm) _AL3_R(ARM_INST_SUB, rd, rn, rm)
#define ARM_SUB_I(rd, rn, imm) _AL3_I(ARM_INST_SUB, rd, rn, imm)
#define ARM_STR_I(rt, rn, off) (ARM_INST_STR_I | (rt) << 12 | (rn) << 16 \
| (off))
#define ARM_TST_R(rn, rm) _AL3_R(ARM_INST_TST, 0, rn, rm)
#define ARM_TST_I(rn, imm) _AL3_I(ARM_INST_TST, 0, rn, imm)
#define ARM_UDIV(rd, rn, rm) (ARM_INST_UDIV | (rd) << 16 | (rn) | (rm) << 8)
#define ARM_UMULL(rd_lo, rd_hi, rn, rm) (ARM_INST_UMULL | (rd_hi) << 16 \
| (rd_lo) << 12 | (rm) << 8 | rn)
#endif /* PFILTER_OPCODES_ARM_H */
......@@ -23,7 +23,6 @@ config HAS_MTU
config NOMADIK_MTU_SCHED_CLOCK
bool
depends on HAS_MTU
select HAVE_SCHED_CLOCK
help
Use the Multi Timer Unit as the sched_clock.
......
......@@ -11,7 +11,6 @@ config PLAT_VERSATILE_LEDS
depends on ARCH_REALVIEW || ARCH_VERSATILE
config PLAT_VERSATILE_SCHED_CLOCK
def_bool y if !ARCH_INTEGRATOR_AP
select HAVE_SCHED_CLOCK
def_bool y
endif
......@@ -11,7 +11,7 @@ config TMS320C6X
select HAVE_DMA_API_DEBUG
select HAVE_GENERIC_HARDIRQS
select HAVE_MEMBLOCK
select HAVE_SPARSE_IRQ
select SPARSE_IRQ
select IRQ_DOMAIN
select OF
select OF_EARLY_FLATTREE
......
......@@ -133,7 +133,6 @@ config PPC
select HAVE_REGS_AND_STACK_ACCESS_API
select HAVE_HW_BREAKPOINT if PERF_EVENTS && PPC_BOOK3S_64
select HAVE_GENERIC_HARDIRQS
select HAVE_SPARSE_IRQ
select SPARSE_IRQ
select IRQ_PER_CPU
select IRQ_DOMAIN
......
......@@ -22,7 +22,7 @@ config SUPERH
select HAVE_SYSCALL_TRACEPOINTS
select HAVE_REGS_AND_STACK_ACCESS_API
select HAVE_GENERIC_HARDIRQS
select HAVE_SPARSE_IRQ
select MAY_HAVE_SPARSE_IRQ
select IRQ_FORCED_THREADING
select RTC_LIB
select GENERIC_ATOMIC64
......
......@@ -20,17 +20,6 @@
*/
#define NO_IRQ_IGNORE ((unsigned int)-1)
/*
* Convert back and forth between INTEVT and IRQ values.
*/
#ifdef CONFIG_CPU_HAS_INTEVT
#define evt2irq(evt) (((evt) >> 5) - 16)
#define irq2evt(irq) (((irq) + 16) << 5)
#else
#define evt2irq(evt) (evt)
#define irq2evt(irq) (irq)
#endif
/*
* Simple Mask Register Support
*/
......
......@@ -69,7 +69,6 @@ config X86
select HAVE_ARCH_JUMP_LABEL
select HAVE_TEXT_POKE_SMP
select HAVE_GENERIC_HARDIRQS
select HAVE_SPARSE_IRQ
select SPARSE_IRQ
select GENERIC_FIND_FIRST_BIT
select GENERIC_IRQ_PROBE
......
......@@ -26,7 +26,6 @@ config CLKSRC_DBX500_PRCMU
config CLKSRC_DBX500_PRCMU_SCHED_CLOCK
bool "Clocksource PRCMU Timer sched_clock"
depends on (CLKSRC_DBX500_PRCMU && !NOMADIK_MTU_SCHED_CLOCK)
select HAVE_SCHED_CLOCK
default y
help
Use the always on PRCMU Timer as sched_clock
......@@ -22,6 +22,8 @@
#include <linux/syscore_ops.h>
#include <linux/slab.h>
#include <mach/irqs.h>
/*
* We handle the GPIOs by banks, each bank covers up to 32 GPIOs with
* one set of registers. The register offsets are organized below:
......
......@@ -9,7 +9,7 @@
*/
#include "internals.h"
static unsigned long dist_handle[NR_IRQS];
static unsigned long dist_handle[INTC_NR_IRQS];
void intc_balancing_enable(unsigned int irq)
{
......
......@@ -42,7 +42,7 @@ unsigned int nr_intc_controllers;
* - this needs to be at least 2 for 5-bit priorities on 7780
*/
static unsigned int default_prio_level = 2; /* 2 - 16 */
static unsigned int intc_prio_level[NR_IRQS]; /* for now */
static unsigned int intc_prio_level[INTC_NR_IRQS]; /* for now */
unsigned int intc_get_dfl_prio_level(void)
{
......
......@@ -13,7 +13,7 @@
#include <linux/spinlock.h>
#include "internals.h"
static unsigned long ack_handle[NR_IRQS];
static unsigned long ack_handle[INTC_NR_IRQS];
static intc_enum __init intc_grp_id(struct intc_desc *desc,
intc_enum enum_id)
......
......@@ -17,7 +17,7 @@
#include <linux/export.h>
#include "internals.h"
static struct intc_map_entry intc_irq_xlate[NR_IRQS];
static struct intc_map_entry intc_irq_xlate[INTC_NR_IRQS];
struct intc_virq_list {
unsigned int irq;
......
......@@ -3,6 +3,23 @@
#include <linux/ioport.h>
#ifdef CONFIG_SUPERH
#define INTC_NR_IRQS 512
#else
#define INTC_NR_IRQS 1024
#endif
/*
* Convert back and forth between INTEVT and IRQ values.
*/
#ifdef CONFIG_CPU_HAS_INTEVT
#define evt2irq(evt) (((evt) >> 5) - 16)
#define irq2evt(irq) (((irq) + 16) << 5)
#else
#define evt2irq(evt) (evt)
#define irq2evt(irq) (irq)
#endif
typedef unsigned char intc_enum;
struct intc_vect {
......
......@@ -13,7 +13,7 @@ config GENERIC_HARDIRQS
# Options selectable by the architecture code
# Make sparse irq Kconfig switch below available
config HAVE_SPARSE_IRQ
config MAY_HAVE_SPARSE_IRQ
bool
# Enable the generic irq autoprobe mechanism
......@@ -71,8 +71,7 @@ config IRQ_FORCED_THREADING
bool
config SPARSE_IRQ
bool "Support sparse irq numbering"
depends on HAVE_SPARSE_IRQ
bool "Support sparse irq numbering" if MAY_HAVE_SPARSE_IRQ
---help---
Sparse irq numbering is useful for distro kernels that want
......
......@@ -2,4 +2,20 @@
# Test for gcc 'asm goto' support
# Copyright (C) 2010, Jason Baron <jbaron@redhat.com>
echo "int main(void) { entry: asm goto (\"\"::::entry); return 0; }" | $@ -x c - -c -o /dev/null >/dev/null 2>&1 && echo "y"
cat << "END" | $@ -x c - -c -o /dev/null >/dev/null 2>&1 && echo "y"
int main(void)
{
#ifdef __arm__
/*
* Not related to asm goto, but used by jump label
* and broken on some ARM GCC versions (see GCC Bug 48637).
*/
static struct { int dummy; int state; } tp;
asm (".long %c0" :: "i" (&tp.state));
#endif
entry:
asm goto ("" :::: entry);
return 0;
}
END
......@@ -21,7 +21,7 @@
#include <sound/ac97_codec.h>
#include <sound/pxa2xx-lib.h>
#include <asm/irq.h>
#include <mach/irqs.h>
#include <mach/regs-ac97.h>
#include <mach/audio.h>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment