]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge remote-tracking branch 'arm/for-next'
authorStephen Rothwell <sfr@canb.auug.org.au>
Thu, 9 Apr 2015 00:33:02 +0000 (10:33 +1000)
committerStephen Rothwell <sfr@canb.auug.org.au>
Thu, 9 Apr 2015 00:33:02 +0000 (10:33 +1000)
88 files changed:
Documentation/devicetree/bindings/arm/pmu.txt
Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-ahb.txt
arch/arm/Kconfig
arch/arm/Makefile
arch/arm/boot/compressed/head.S
arch/arm/include/asm/Kbuild
arch/arm/include/asm/auxvec.h [new file with mode: 0644]
arch/arm/include/asm/cputype.h
arch/arm/include/asm/elf.h
arch/arm/include/asm/futex.h
arch/arm/include/asm/mmu.h
arch/arm/include/asm/pmu.h
arch/arm/include/asm/smp_plat.h
arch/arm/include/asm/uaccess.h
arch/arm/include/asm/unified.h
arch/arm/include/asm/vdso.h [new file with mode: 0644]
arch/arm/include/asm/vdso_datapage.h [new file with mode: 0644]
arch/arm/include/asm/word-at-a-time.h
arch/arm/include/uapi/asm/Kbuild
arch/arm/include/uapi/asm/auxvec.h [new file with mode: 0644]
arch/arm/kernel/Makefile
arch/arm/kernel/asm-offsets.c
arch/arm/kernel/bios32.c
arch/arm/kernel/entry-armv.S
arch/arm/kernel/head.S
arch/arm/kernel/hibernate.c
arch/arm/kernel/machine_kexec.c
arch/arm/kernel/module.c
arch/arm/kernel/perf_event.c
arch/arm/kernel/perf_event_cpu.c
arch/arm/kernel/perf_event_v7.c
arch/arm/kernel/process.c
arch/arm/kernel/psci-call.S [new file with mode: 0644]
arch/arm/kernel/psci.c
arch/arm/kernel/reboot.c [new file with mode: 0644]
arch/arm/kernel/reboot.h [new file with mode: 0644]
arch/arm/kernel/return_address.c
arch/arm/kernel/setup.c
arch/arm/kernel/sleep.S
arch/arm/kernel/smp.c
arch/arm/kernel/swp_emulate.c
arch/arm/kernel/vdso.c [new file with mode: 0644]
arch/arm/kernel/vmlinux.lds.S
arch/arm/lib/clear_user.S
arch/arm/lib/copy_to_user.S
arch/arm/lib/csumpartialcopyuser.S
arch/arm/mach-exynos/sleep.S
arch/arm/mach-s5pv210/sleep.S
arch/arm/mm/Kconfig
arch/arm/mm/alignment.c
arch/arm/mm/cache-l2x0.c
arch/arm/mm/cache-v7.S
arch/arm/mm/dma-mapping.c
arch/arm/mm/proc-arm1020.S
arch/arm/mm/proc-arm1020e.S
arch/arm/mm/proc-arm1022.S
arch/arm/mm/proc-arm1026.S
arch/arm/mm/proc-arm720.S
arch/arm/mm/proc-arm740.S
arch/arm/mm/proc-arm7tdmi.S
arch/arm/mm/proc-arm920.S
arch/arm/mm/proc-arm922.S
arch/arm/mm/proc-arm925.S
arch/arm/mm/proc-arm926.S
arch/arm/mm/proc-arm940.S
arch/arm/mm/proc-arm946.S
arch/arm/mm/proc-arm9tdmi.S
arch/arm/mm/proc-fa526.S
arch/arm/mm/proc-feroceon.S
arch/arm/mm/proc-macros.S
arch/arm/mm/proc-mohawk.S
arch/arm/mm/proc-sa110.S
arch/arm/mm/proc-sa1100.S
arch/arm/mm/proc-v6.S
arch/arm/mm/proc-v7.S
arch/arm/mm/proc-v7m.S
arch/arm/mm/proc-xsc3.S
arch/arm/mm/proc-xscale.S
arch/arm/nwfpe/entry.S
arch/arm/vdso/.gitignore [new file with mode: 0644]
arch/arm/vdso/Makefile [new file with mode: 0644]
arch/arm/vdso/datapage.S [new file with mode: 0644]
arch/arm/vdso/vdso.S [new file with mode: 0644]
arch/arm/vdso/vdso.lds.S [new file with mode: 0644]
arch/arm/vdso/vdsomunge.c [new file with mode: 0644]
arch/arm/vdso/vgettimeofday.c [new file with mode: 0644]
drivers/amba/tegra-ahb.c
include/asm-generic/vmlinux.lds.h

index 75ef91d08f3bd2cbc402326598ead0e34663e790..6e54a9d88b7ab753dd2063a03dd6b39daff8e8db 100644 (file)
@@ -18,6 +18,8 @@ Required properties:
        "arm,arm11mpcore-pmu"
        "arm,arm1176-pmu"
        "arm,arm1136-pmu"
+       "qcom,scorpion-pmu"
+       "qcom,scorpion-mp-pmu"
        "qcom,krait-pmu"
 - interrupts : 1 combined interrupt or 1 per core. If the interrupt is a per-cpu
                interrupt (PPI) then 1 interrupt should be specified.
index 067c9790062f7e1ab42aa1835e095ca076babbe4..9a4295b545395bb3673299e68d08cfad2a09365e 100644 (file)
@@ -5,9 +5,12 @@ Required properties:
   Tegra30, must contain "nvidia,tegra30-ahb".  Otherwise, must contain
   '"nvidia,<chip>-ahb", "nvidia,tegra30-ahb"' where <chip> is tegra124,
   tegra132, or tegra210.
-- reg : Should contain 1 register ranges(address and length)
+- reg : Should contain 1 register ranges(address and length).  For
+  Tegra20, Tegra30, and Tegra114 chips, the value must be <0x6000c004
+  0x10c>.  For Tegra124, Tegra132 and Tegra210 chips, the value should
+  be be <0x6000c000 0x150>.
 
-Example:
+Example (for a Tegra20 chip):
        ahb: ahb@6000c004 {
                compatible = "nvidia,tegra20-ahb";
                reg = <0x6000c004 0x10c>; /* AHB Arbitration + Gizmo Controller */
index cf4c0c99aa253f3f69ecc08a07f0c5a695e63640..c23a40a3e2c1c6ab0221864412a992bb6b0155df 100644 (file)
@@ -21,6 +21,7 @@ config ARM
        select GENERIC_IDLE_POLL_SETUP
        select GENERIC_IRQ_PROBE
        select GENERIC_IRQ_SHOW
+       select GENERIC_IRQ_SHOW_LEVEL
        select GENERIC_PCI_IOMAP
        select GENERIC_SCHED_CLOCK
        select GENERIC_SMP_IDLE_THREAD
@@ -1344,7 +1345,7 @@ config SMP
          If you don't know what to do here, say N.
 
 config SMP_ON_UP
-       bool "Allow booting SMP kernel on uniprocessor systems (EXPERIMENTAL)"
+       bool "Allow booting SMP kernel on uniprocessor systems"
        depends on SMP && !XIP_KERNEL && MMU
        default y
        help
index eb7bb511f853d975d67c0ee26c1167b2d5054279..5575d9fa8806cd5f74409242a7041f2e96b16453 100644 (file)
@@ -13,7 +13,7 @@
 # Ensure linker flags are correct
 LDFLAGS                :=
 
-LDFLAGS_vmlinux        :=-p --no-undefined -X
+LDFLAGS_vmlinux        :=-p --no-undefined -X --pic-veneer
 ifeq ($(CONFIG_CPU_ENDIAN_BE8),y)
 LDFLAGS_vmlinux        += --be8
 LDFLAGS_MODULE += --be8
@@ -264,6 +264,7 @@ core-$(CONFIG_FPE_FASTFPE)  += $(FASTFPE_OBJ)
 core-$(CONFIG_VFP)             += arch/arm/vfp/
 core-$(CONFIG_XEN)             += arch/arm/xen/
 core-$(CONFIG_KVM_ARM_HOST)    += arch/arm/kvm/
+core-$(CONFIG_VDSO)            += arch/arm/vdso/
 
 # If we have a machine-specific directory, then include it in the build.
 core-y                         += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/
@@ -321,6 +322,12 @@ dtbs: prepare scripts
 dtbs_install:
        $(Q)$(MAKE) $(dtbinst)=$(boot)/dts
 
+PHONY += vdso_install
+vdso_install:
+ifeq ($(CONFIG_VDSO),y)
+       $(Q)$(MAKE) $(build)=arch/arm/vdso $@
+endif
+
 # We use MRPROPER_FILES and CLEAN_FILES now
 archclean:
        $(Q)$(MAKE) $(clean)=$(boot)
@@ -345,4 +352,5 @@ define archhelp
   echo  '                  Install using (your) ~/bin/$(INSTALLKERNEL) or'
   echo  '                  (distribution) /sbin/$(INSTALLKERNEL) or'
   echo  '                  install to $$(INSTALL_PATH) and run lilo'
+  echo  '  vdso_install  - Install unstripped vdso.so to $$(INSTALL_MOD_PATH)/vdso'
 endef
index c41a793b519c2817cfc5a48bee38235812874fc2..2c45b5709fa494828560891cde6e64926f1e1581 100644 (file)
  */
 #include <linux/linkage.h>
 #include <asm/assembler.h>
+#include <asm/v7m.h>
+
+ AR_CLASS(     .arch   armv7-a )
+ M_CLASS(      .arch   armv7-m )
 
-       .arch   armv7-a
 /*
  * Debugging stuff
  *
  * sort out different calling conventions
  */
                .align
-               .arm                            @ Always enter in ARM state
+               /*
+                * Always enter in ARM state for CPUs that support the ARM ISA.
+                * As of today (2014) that's exactly the members of the A and R
+                * classes.
+                */
+ AR_CLASS(     .arm    )
 start:
                .type   start,#function
                .rept   7
@@ -132,14 +140,15 @@ start:
 
  THUMB(                .thumb                  )
 1:
- ARM_BE8(      setend  be )                    @ go BE8 if compiled for BE8
-               mrs     r9, cpsr
+ ARM_BE8(      setend  be              )       @ go BE8 if compiled for BE8
+ AR_CLASS(     mrs     r9, cpsr        )
 #ifdef CONFIG_ARM_VIRT_EXT
                bl      __hyp_stub_install      @ get into SVC mode, reversibly
 #endif
                mov     r7, r1                  @ save architecture ID
                mov     r8, r2                  @ save atags pointer
 
+#ifndef CONFIG_CPU_V7M
                /*
                 * Booting from Angel - need to enter SVC mode and disable
                 * FIQs/IRQs (numeric definitions from angel arm.h source).
@@ -155,6 +164,7 @@ not_angel:
                safe_svcmode_maskall r0
                msr     spsr_cxsf, r9           @ Save the CPU boot mode in
                                                @ SPSR
+#endif
                /*
                 * Note that some cache flushing and other stuff may
                 * be needed here - is there an Angel SWI call for this?
@@ -168,9 +178,26 @@ not_angel:
                .text
 
 #ifdef CONFIG_AUTO_ZRELADDR
-               @ determine final kernel image address
+               /*
+                * Find the start of physical memory.  As we are executing
+                * without the MMU on, we are in the physical address space.
+                * We just need to get rid of any offset by aligning the
+                * address.
+                *
+                * This alignment is a balance between the requirements of
+                * different platforms - we have chosen 128MB to allow
+                * platforms which align the start of their physical memory
+                * to 128MB to use this feature, while allowing the zImage
+                * to be placed within the first 128MB of memory on other
+                * platforms.  Increasing the alignment means we place
+                * stricter alignment requirements on the start of physical
+                * memory, but relaxing it means that we break people who
+                * are already placing their zImage in (eg) the top 64MB
+                * of this range.
+                */
                mov     r4, pc
                and     r4, r4, #0xf8000000
+               /* Determine final kernel image address. */
                add     r4, r4, #TEXT_OFFSET
 #else
                ldr     r4, =zreladdr
@@ -810,6 +837,16 @@ __common_mmu_cache_on:
 call_cache_fn: adr     r12, proc_types
 #ifdef CONFIG_CPU_CP15
                mrc     p15, 0, r9, c0, c0      @ get processor ID
+#elif defined(CONFIG_CPU_V7M)
+               /*
+                * On v7-M the processor id is located in the V7M_SCB_CPUID
+                * register, but as cache handling is IMPLEMENTATION DEFINED on
+                * v7-M (if existant at all) we just return early here.
+                * If V7M_SCB_CPUID were used the cpu ID functions (i.e.
+                * __armv7_mmu_cache_{on,off,flush}) would be selected which
+                * use cp15 registers that are not implemented on v7-M.
+                */
+               bx      lr
 #else
                ldr     r9, =CONFIG_PROCESSOR_ID
 #endif
@@ -1310,8 +1347,9 @@ __hyp_reentry_vectors:
 
 __enter_kernel:
                mov     r0, #0                  @ must be 0
- ARM(          mov     pc, r4  )               @ call kernel
- THUMB(                bx      r4      )               @ entry point is always ARM
+ ARM(          mov     pc, r4          )       @ call kernel
+ M_CLASS(      add     r4, r4, #1      )       @ enter in Thumb mode for M class
+ THUMB(                bx      r4              )       @ entry point is always ARM for A/R classes
 
 reloc_code_end:
 
index fe74c0d1e485f01588ec21a927a852a0b0ca156e..eb0f43f3e3f1b75409cee347795ccb5b9dcafcd5 100644 (file)
@@ -1,6 +1,5 @@
 
 
-generic-y += auxvec.h
 generic-y += bitsperlong.h
 generic-y += cputime.h
 generic-y += current.h
diff --git a/arch/arm/include/asm/auxvec.h b/arch/arm/include/asm/auxvec.h
new file mode 100644 (file)
index 0000000..fbd388c
--- /dev/null
@@ -0,0 +1 @@
+#include <uapi/asm/auxvec.h>
index 819777d0e91f92cb91ff8c1933c480cb1bb80b91..85e374f873ac7b182709ef7552002188d9d3e1e3 100644 (file)
@@ -253,4 +253,20 @@ static inline int cpu_is_pj4(void)
 #else
 #define cpu_is_pj4()   0
 #endif
+
+static inline int __attribute_const__ cpuid_feature_extract_field(u32 features,
+                                                                 int field)
+{
+       int feature = (features >> field) & 15;
+
+       /* feature registers are signed values */
+       if (feature > 8)
+               feature -= 16;
+
+       return feature;
+}
+
+#define cpuid_feature_extract(reg, field) \
+       cpuid_feature_extract_field(read_cpuid_ext(reg), field)
+
 #endif
index 674d03f4ba1545054ce4dcc33280f99b32e151c4..e2f4781630f6137565f509f9c31c4ea73262b5a3 100644 (file)
@@ -1,7 +1,9 @@
 #ifndef __ASMARM_ELF_H
 #define __ASMARM_ELF_H
 
+#include <asm/auxvec.h>
 #include <asm/hwcap.h>
+#include <asm/vdso_datapage.h>
 
 /*
  * ELF register definitions..
@@ -130,6 +132,13 @@ extern unsigned long arch_randomize_brk(struct mm_struct *mm);
 #define arch_randomize_brk arch_randomize_brk
 
 #ifdef CONFIG_MMU
+#ifdef CONFIG_VDSO
+#define ARCH_DLINFO                                            \
+do {                                                           \
+       NEW_AUX_ENT(AT_SYSINFO_EHDR,                            \
+                   (elf_addr_t)current->mm->context.vdso);     \
+} while (0)
+#endif
 #define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1
 struct linux_binprm;
 int arch_setup_additional_pages(struct linux_binprm *, int);
index 53e69dae796f32e495ab262953d4b52cce0cc303..4e78065a16aa3c6a3dae5db147f36fda00dcf18a 100644 (file)
@@ -13,7 +13,7 @@
        "       .align  3\n"                                    \
        "       .long   1b, 4f, 2b, 4f\n"                       \
        "       .popsection\n"                                  \
-       "       .pushsection .fixup,\"ax\"\n"                   \
+       "       .pushsection .text.fixup,\"ax\"\n"              \
        "       .align  2\n"                                    \
        "4:     mov     %0, " err_reg "\n"                      \
        "       b       3b\n"                                   \
index 64fd15159b7de710b81a47c0aa9d6bab3af1d691..a5b47421059dc34153f7450a1cc7d2baf21200b5 100644 (file)
@@ -11,6 +11,9 @@ typedef struct {
 #endif
        unsigned int    vmalloc_seq;
        unsigned long   sigpage;
+#ifdef CONFIG_VDSO
+       unsigned long   vdso;
+#endif
 } mm_context_t;
 
 #ifdef CONFIG_CPU_HAS_ASID
index b1596bd59129049ab3dfd46a95aff4e75531fe90..675e4ab79f68948786733ab2652239e0fe98d049 100644 (file)
@@ -92,6 +92,7 @@ struct pmu_hw_events {
 struct arm_pmu {
        struct pmu      pmu;
        cpumask_t       active_irqs;
+       int             *irq_affinity;
        char            *name;
        irqreturn_t     (*handle_irq)(int irq_num, void *dev);
        void            (*enable)(struct perf_event *event);
index 0ad7d490ee6f2657b1504359d362ad8d886bee91..993e5224d8f7eeeb09f4c2a5358a97073c67c3a6 100644 (file)
@@ -104,6 +104,7 @@ static inline u32 mpidr_hash_size(void)
        return 1 << mpidr_hash.bits;
 }
 
+extern int platform_can_secondary_boot(void);
 extern int platform_can_cpu_hotplug(void);
 
 #endif
index ce0786efd26c3485d28baa6b7857e35350c1336d..74b17d09ef7aa54cb98d22ccf5f068b4c39971be 100644 (file)
@@ -315,7 +315,7 @@ do {                                                                        \
        __asm__ __volatile__(                                   \
        "1:     " TUSER(ldrb) " %1,[%2],#0\n"                   \
        "2:\n"                                                  \
-       "       .pushsection .fixup,\"ax\"\n"                   \
+       "       .pushsection .text.fixup,\"ax\"\n"              \
        "       .align  2\n"                                    \
        "3:     mov     %0, %3\n"                               \
        "       mov     %1, #0\n"                               \
@@ -351,7 +351,7 @@ do {                                                                        \
        __asm__ __volatile__(                                   \
        "1:     " TUSER(ldr) "  %1,[%2],#0\n"                   \
        "2:\n"                                                  \
-       "       .pushsection .fixup,\"ax\"\n"                   \
+       "       .pushsection .text.fixup,\"ax\"\n"              \
        "       .align  2\n"                                    \
        "3:     mov     %0, %3\n"                               \
        "       mov     %1, #0\n"                               \
@@ -397,7 +397,7 @@ do {                                                                        \
        __asm__ __volatile__(                                   \
        "1:     " TUSER(strb) " %1,[%2],#0\n"                   \
        "2:\n"                                                  \
-       "       .pushsection .fixup,\"ax\"\n"                   \
+       "       .pushsection .text.fixup,\"ax\"\n"              \
        "       .align  2\n"                                    \
        "3:     mov     %0, %3\n"                               \
        "       b       2b\n"                                   \
@@ -430,7 +430,7 @@ do {                                                                        \
        __asm__ __volatile__(                                   \
        "1:     " TUSER(str) "  %1,[%2],#0\n"                   \
        "2:\n"                                                  \
-       "       .pushsection .fixup,\"ax\"\n"                   \
+       "       .pushsection .text.fixup,\"ax\"\n"              \
        "       .align  2\n"                                    \
        "3:     mov     %0, %3\n"                               \
        "       b       2b\n"                                   \
@@ -458,7 +458,7 @@ do {                                                                        \
  THUMB(        "1:     " TUSER(str) "  " __reg_oper1 ", [%1]\n"        ) \
  THUMB(        "2:     " TUSER(str) "  " __reg_oper0 ", [%1, #4]\n"    ) \
        "3:\n"                                                  \
-       "       .pushsection .fixup,\"ax\"\n"                   \
+       "       .pushsection .text.fixup,\"ax\"\n"              \
        "       .align  2\n"                                    \
        "4:     mov     %0, %3\n"                               \
        "       b       3b\n"                                   \
index b88beaba6b4a5cf9c0ccded73723c4ea41539167..200f9a7cd623e613acd89a3d0fbb219b48232604 100644 (file)
        .syntax unified
 #endif
 
+#ifdef CONFIG_CPU_V7M
+#define AR_CLASS(x...)
+#define M_CLASS(x...)  x
+#else
+#define AR_CLASS(x...) x
+#define M_CLASS(x...)
+#endif
+
 #ifdef CONFIG_THUMB2_KERNEL
 
 #if __GNUC__ < 4
diff --git a/arch/arm/include/asm/vdso.h b/arch/arm/include/asm/vdso.h
new file mode 100644 (file)
index 0000000..d0295f1
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef __ASM_VDSO_H
+#define __ASM_VDSO_H
+
+#ifdef __KERNEL__
+
+#ifndef __ASSEMBLY__
+
+struct mm_struct;
+
+#ifdef CONFIG_VDSO
+
+void arm_install_vdso(struct mm_struct *mm, unsigned long addr);
+
+extern char vdso_start, vdso_end;
+
+extern unsigned int vdso_total_pages;
+
+#else /* CONFIG_VDSO */
+
+static inline void arm_install_vdso(struct mm_struct *mm, unsigned long addr)
+{
+}
+
+#define vdso_total_pages 0
+
+#endif /* CONFIG_VDSO */
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __KERNEL__ */
+
+#endif /* __ASM_VDSO_H */
diff --git a/arch/arm/include/asm/vdso_datapage.h b/arch/arm/include/asm/vdso_datapage.h
new file mode 100644 (file)
index 0000000..9be2594
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Adapted from arm64 version.
+ *
+ * Copyright (C) 2012 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_VDSO_DATAPAGE_H
+#define __ASM_VDSO_DATAPAGE_H
+
+#ifdef __KERNEL__
+
+#ifndef __ASSEMBLY__
+
+#include <asm/page.h>
+
+/* Try to be cache-friendly on systems that don't implement the
+ * generic timer: fit the unconditionally updated fields in the first
+ * 32 bytes.
+ */
+struct vdso_data {
+       u32 seq_count;          /* sequence count - odd during updates */
+       u16 tk_is_cntvct;       /* fall back to syscall if false */
+       u16 cs_shift;           /* clocksource shift */
+       u32 xtime_coarse_sec;   /* coarse time */
+       u32 xtime_coarse_nsec;
+
+       u32 wtm_clock_sec;      /* wall to monotonic offset */
+       u32 wtm_clock_nsec;
+       u32 xtime_clock_sec;    /* CLOCK_REALTIME - seconds */
+       u32 cs_mult;            /* clocksource multiplier */
+
+       u64 cs_cycle_last;      /* last cycle value */
+       u64 cs_mask;            /* clocksource mask */
+
+       u64 xtime_clock_snsec;  /* CLOCK_REALTIME sub-ns base */
+       u32 tz_minuteswest;     /* timezone info for gettimeofday(2) */
+       u32 tz_dsttime;
+};
+
+union vdso_data_store {
+       struct vdso_data data;
+       u8 page[PAGE_SIZE];
+};
+
+#endif /* !__ASSEMBLY__ */
+
+#endif /* __KERNEL__ */
+
+#endif /* __ASM_VDSO_DATAPAGE_H */
index a6d0a29861e7cef407a5514c5a2d8687726d4a30..5831dce4b51c33e9b95bd8d2300467c557143eb6 100644 (file)
@@ -71,7 +71,7 @@ static inline unsigned long load_unaligned_zeropad(const void *addr)
        asm(
        "1:     ldr     %0, [%2]\n"
        "2:\n"
-       "       .pushsection .fixup,\"ax\"\n"
+       "       .pushsection .text.fixup,\"ax\"\n"
        "       .align 2\n"
        "3:     and     %1, %2, #0x3\n"
        "       bic     %2, %2, #0x3\n"
index 70a1c9da30ca39d4d4d79e8e73c3b8aec0d607e3..a1c05f93d920dd245287d39f7bd8721cb78fc732 100644 (file)
@@ -1,6 +1,7 @@
 # UAPI Header export list
 include include/uapi/asm-generic/Kbuild.asm
 
+header-y += auxvec.h
 header-y += byteorder.h
 header-y += fcntl.h
 header-y += hwcap.h
diff --git a/arch/arm/include/uapi/asm/auxvec.h b/arch/arm/include/uapi/asm/auxvec.h
new file mode 100644 (file)
index 0000000..cb02a76
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef __ASM_AUXVEC_H
+#define __ASM_AUXVEC_H
+
+/* VDSO location */
+#define AT_SYSINFO_EHDR        33
+
+#endif
index 902397dd100070165a4ed62950ad24bbf3d5594b..ba5f83226011849e9dacfb6429c9df9f6b8be459 100644 (file)
@@ -16,7 +16,7 @@ CFLAGS_REMOVE_return_address.o = -pg
 # Object file lists.
 
 obj-y          := elf.o entry-common.o irq.o opcodes.o \
-                  process.o ptrace.o return_address.o \
+                  process.o ptrace.o reboot.o return_address.o \
                   setup.o signal.o sigreturn_codes.o \
                   stacktrace.o sys_arm.o time.o traps.o
 
@@ -75,6 +75,7 @@ obj-$(CONFIG_HW_PERF_EVENTS)  += perf_event.o perf_event_cpu.o
 CFLAGS_pj4-cp0.o               := -marm
 AFLAGS_iwmmxt.o                        := -Wa,-mcpu=iwmmxt
 obj-$(CONFIG_ARM_CPU_TOPOLOGY)  += topology.o
+obj-$(CONFIG_VDSO)             += vdso.o
 
 ifneq ($(CONFIG_ARCH_EBSA110),y)
   obj-y                += io.o
@@ -86,7 +87,7 @@ obj-$(CONFIG_EARLY_PRINTK)    += early_printk.o
 
 obj-$(CONFIG_ARM_VIRT_EXT)     += hyp-stub.o
 ifeq ($(CONFIG_ARM_PSCI),y)
-obj-y                          += psci.o
+obj-y                          += psci.o psci-call.o
 obj-$(CONFIG_SMP)              += psci_smp.o
 endif
 
index 2d2d6087b9b105d5dadcd66f9821deefe50d1e66..9147008f0d517c93eefa53668760405aea30a763 100644 (file)
@@ -25,6 +25,7 @@
 #include <asm/memory.h>
 #include <asm/procinfo.h>
 #include <asm/suspend.h>
+#include <asm/vdso_datapage.h>
 #include <asm/hardware/cache-l2x0.h>
 #include <linux/kbuild.h>
 
@@ -209,6 +210,10 @@ int main(void)
   DEFINE(KVM_VGIC_VCTRL,       offsetof(struct kvm, arch.vgic.vctrl_base));
 #endif
   DEFINE(KVM_VTTBR,            offsetof(struct kvm, arch.vttbr));
+#endif
+  BLANK();
+#ifdef CONFIG_VDSO
+  DEFINE(VDSO_DATA_SIZE,       sizeof(union vdso_data_store));
 #endif
   return 0; 
 }
index ab19b7c03423690adac07fd99e525a5f4ac3f359..fcbbbb1b9e9578b64371785385b6074e256ff26d 100644 (file)
@@ -618,21 +618,15 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
 int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
                        enum pci_mmap_state mmap_state, int write_combine)
 {
-       struct pci_sys_data *root = dev->sysdata;
-       unsigned long phys;
-
-       if (mmap_state == pci_mmap_io) {
+       if (mmap_state == pci_mmap_io)
                return -EINVAL;
-       } else {
-               phys = vma->vm_pgoff + (root->mem_offset >> PAGE_SHIFT);
-       }
 
        /*
         * Mark this as IO
         */
        vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 
-       if (remap_pfn_range(vma, vma->vm_start, phys,
+       if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
                             vma->vm_end - vma->vm_start,
                             vma->vm_page_prot))
                return -EAGAIN;
index 672b21942fff77581d13959039b518a36a1e1eef..570306c494068f2ac8f841eb3344b4f981f7a3bb 100644 (file)
@@ -545,7 +545,7 @@ ENDPROC(__und_usr)
 /*
  * The out of line fixup for the ldrt instructions above.
  */
-       .pushsection .fixup, "ax"
+       .pushsection .text.fixup, "ax"
        .align  2
 4:     str     r4, [sp, #S_PC]                 @ retry current instruction
        ret     r9
index 01963273c07a7b187be24bb2a4974b9fc826ebcf..3637973a9708bc4f9e8f457b7c04307ca6e2212b 100644 (file)
@@ -138,9 +138,9 @@ ENTRY(stext)
                                                @ mmu has been enabled
        adr     lr, BSYM(1f)                    @ return (PIC) address
        mov     r8, r4                          @ set TTBR1 to swapper_pg_dir
- ARM(  add     pc, r10, #PROCINFO_INITFUNC     )
- THUMB(        add     r12, r10, #PROCINFO_INITFUNC    )
- THUMB(        ret     r12                             )
+       ldr     r12, [r10, #PROCINFO_INITFUNC]
+       add     r12, r12, r10
+       ret     r12
 1:     b       __enable_mmu
 ENDPROC(stext)
        .ltorg
@@ -386,10 +386,10 @@ ENTRY(secondary_startup)
        ldr     r8, [r7, lr]                    @ get secondary_data.swapper_pg_dir
        adr     lr, BSYM(__enable_mmu)          @ return address
        mov     r13, r12                        @ __secondary_switched address
- ARM(  add     pc, r10, #PROCINFO_INITFUNC     ) @ initialise processor
-                                                 @ (return control reg)
THUMB(        add     r12, r10, #PROCINFO_INITFUNC    )
- THUMB(        ret     r12                             )
+       ldr     r12, [r10, #PROCINFO_INITFUNC]
+       add     r12, r12, r10                   @ initialise processor
                                              @ (return control reg)
+       ret     r12
 ENDPROC(secondary_startup)
 ENDPROC(secondary_startup_arm)
 
index c4cc50e58c13c3e032031339852c012ca7b344ca..a71501ff6f1877fc9813fd4c3e10c51ae36f04e7 100644 (file)
@@ -22,6 +22,7 @@
 #include <asm/suspend.h>
 #include <asm/memory.h>
 #include <asm/sections.h>
+#include "reboot.h"
 
 int pfn_is_nosave(unsigned long pfn)
 {
@@ -61,7 +62,7 @@ static int notrace arch_save_image(unsigned long unused)
 
        ret = swsusp_save();
        if (ret == 0)
-               soft_restart(virt_to_phys(cpu_resume));
+               _soft_restart(virt_to_phys(cpu_resume), false);
        return ret;
 }
 
@@ -86,7 +87,7 @@ static void notrace arch_restore_image(void *unused)
        for (pbe = restore_pblist; pbe; pbe = pbe->next)
                copy_page(pbe->orig_address, pbe->address);
 
-       soft_restart(virt_to_phys(cpu_resume));
+       _soft_restart(virt_to_phys(cpu_resume), false);
 }
 
 static u64 resume_stack[PAGE_SIZE/2/sizeof(u64)] __nosavedata;
@@ -99,7 +100,6 @@ static u64 resume_stack[PAGE_SIZE/2/sizeof(u64)] __nosavedata;
  */
 int swsusp_arch_resume(void)
 {
-       extern void call_with_stack(void (*fn)(void *), void *arg, void *sp);
        call_with_stack(arch_restore_image, 0,
                resume_stack + ARRAY_SIZE(resume_stack));
        return 0;
index de2b085ad7535da771a173ed855bcfdee4926c99..8bf3b7c098881b951df038575c6baf14e84df7b9 100644 (file)
@@ -46,7 +46,8 @@ int machine_kexec_prepare(struct kimage *image)
         * and implements CPU hotplug for the current HW. If not, we won't be
         * able to kexec reliably, so fail the prepare operation.
         */
-       if (num_possible_cpus() > 1 && !platform_can_cpu_hotplug())
+       if (num_possible_cpus() > 1 && platform_can_secondary_boot() &&
+           !platform_can_cpu_hotplug())
                return -EINVAL;
 
        /*
index 2e11961f65ae0a005d53a22c45753879c7b6c904..af791f4a620592fd66bac091fc45498c70b0d39b 100644 (file)
@@ -98,14 +98,19 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
                case R_ARM_PC24:
                case R_ARM_CALL:
                case R_ARM_JUMP24:
+                       if (sym->st_value & 3) {
+                               pr_err("%s: section %u reloc %u sym '%s': unsupported interworking call (ARM -> Thumb)\n",
+                                      module->name, relindex, i, symname);
+                               return -ENOEXEC;
+                       }
+
                        offset = __mem_to_opcode_arm(*(u32 *)loc);
                        offset = (offset & 0x00ffffff) << 2;
                        if (offset & 0x02000000)
                                offset -= 0x04000000;
 
                        offset += sym->st_value - loc;
-                       if (offset & 3 ||
-                           offset <= (s32)0xfe000000 ||
+                       if (offset <= (s32)0xfe000000 ||
                            offset >= (s32)0x02000000) {
                                pr_err("%s: section %u reloc %u sym '%s': relocation %u out of range (%#lx -> %#x)\n",
                                       module->name, relindex, i, symname,
@@ -155,6 +160,22 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
 #ifdef CONFIG_THUMB2_KERNEL
                case R_ARM_THM_CALL:
                case R_ARM_THM_JUMP24:
+                       /*
+                        * For function symbols, only Thumb addresses are
+                        * allowed (no interworking).
+                        *
+                        * For non-function symbols, the destination
+                        * has no specific ARM/Thumb disposition, so
+                        * the branch is resolved under the assumption
+                        * that interworking is not required.
+                        */
+                       if (ELF32_ST_TYPE(sym->st_info) == STT_FUNC &&
+                           !(sym->st_value & 1)) {
+                               pr_err("%s: section %u reloc %u sym '%s': unsupported interworking call (Thumb -> ARM)\n",
+                                      module->name, relindex, i, symname);
+                               return -ENOEXEC;
+                       }
+
                        upper = __mem_to_opcode_thumb16(*(u16 *)loc);
                        lower = __mem_to_opcode_thumb16(*(u16 *)(loc + 2));
 
@@ -182,18 +203,7 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
                                offset -= 0x02000000;
                        offset += sym->st_value - loc;
 
-                       /*
-                        * For function symbols, only Thumb addresses are
-                        * allowed (no interworking).
-                        *
-                        * For non-function symbols, the destination
-                        * has no specific ARM/Thumb disposition, so
-                        * the branch is resolved under the assumption
-                        * that interworking is not required.
-                        */
-                       if ((ELF32_ST_TYPE(sym->st_info) == STT_FUNC &&
-                               !(offset & 1)) ||
-                           offset <= (s32)0xff000000 ||
+                       if (offset <= (s32)0xff000000 ||
                            offset >= (s32)0x01000000) {
                                pr_err("%s: section %u reloc %u sym '%s': relocation %u out of range (%#lx -> %#x)\n",
                                       module->name, relindex, i, symname,
index 557e128e4df08ce711d4bab89952eae0f1d6d7ea..4a86a0133ac30cab95b9a461636b7961f6bd86e2 100644 (file)
@@ -259,20 +259,29 @@ out:
 }
 
 static int
-validate_event(struct pmu_hw_events *hw_events,
-              struct perf_event *event)
+validate_event(struct pmu *pmu, struct pmu_hw_events *hw_events,
+                              struct perf_event *event)
 {
-       struct arm_pmu *armpmu = to_arm_pmu(event->pmu);
+       struct arm_pmu *armpmu;
 
        if (is_software_event(event))
                return 1;
 
+       /*
+        * Reject groups spanning multiple HW PMUs (e.g. CPU + CCI). The
+        * core perf code won't check that the pmu->ctx == leader->ctx
+        * until after pmu->event_init(event).
+        */
+       if (event->pmu != pmu)
+               return 0;
+
        if (event->state < PERF_EVENT_STATE_OFF)
                return 1;
 
        if (event->state == PERF_EVENT_STATE_OFF && !event->attr.enable_on_exec)
                return 1;
 
+       armpmu = to_arm_pmu(event->pmu);
        return armpmu->get_event_idx(hw_events, event) >= 0;
 }
 
@@ -288,15 +297,15 @@ validate_group(struct perf_event *event)
         */
        memset(&fake_pmu.used_mask, 0, sizeof(fake_pmu.used_mask));
 
-       if (!validate_event(&fake_pmu, leader))
+       if (!validate_event(event->pmu, &fake_pmu, leader))
                return -EINVAL;
 
        list_for_each_entry(sibling, &leader->sibling_list, group_entry) {
-               if (!validate_event(&fake_pmu, sibling))
+               if (!validate_event(event->pmu, &fake_pmu, sibling))
                        return -EINVAL;
        }
 
-       if (!validate_event(&fake_pmu, event))
+       if (!validate_event(event->pmu, &fake_pmu, event))
                return -EINVAL;
 
        return 0;
index 61b53c46edfa7556827ae552082e79ece19df909..91c7ba182dcdd9b9e84ce8f5222181b32922deaf 100644 (file)
@@ -92,11 +92,16 @@ static void cpu_pmu_free_irq(struct arm_pmu *cpu_pmu)
                free_percpu_irq(irq, &hw_events->percpu_pmu);
        } else {
                for (i = 0; i < irqs; ++i) {
-                       if (!cpumask_test_and_clear_cpu(i, &cpu_pmu->active_irqs))
+                       int cpu = i;
+
+                       if (cpu_pmu->irq_affinity)
+                               cpu = cpu_pmu->irq_affinity[i];
+
+                       if (!cpumask_test_and_clear_cpu(cpu, &cpu_pmu->active_irqs))
                                continue;
                        irq = platform_get_irq(pmu_device, i);
                        if (irq >= 0)
-                               free_irq(irq, per_cpu_ptr(&hw_events->percpu_pmu, i));
+                               free_irq(irq, per_cpu_ptr(&hw_events->percpu_pmu, cpu));
                }
        }
 }
@@ -128,32 +133,37 @@ static int cpu_pmu_request_irq(struct arm_pmu *cpu_pmu, irq_handler_t handler)
                on_each_cpu(cpu_pmu_enable_percpu_irq, &irq, 1);
        } else {
                for (i = 0; i < irqs; ++i) {
+                       int cpu = i;
+
                        err = 0;
                        irq = platform_get_irq(pmu_device, i);
                        if (irq < 0)
                                continue;
 
+                       if (cpu_pmu->irq_affinity)
+                               cpu = cpu_pmu->irq_affinity[i];
+
                        /*
                         * If we have a single PMU interrupt that we can't shift,
                         * assume that we're running on a uniprocessor machine and
                         * continue. Otherwise, continue without this interrupt.
                         */
-                       if (irq_set_affinity(irq, cpumask_of(i)) && irqs > 1) {
+                       if (irq_set_affinity(irq, cpumask_of(cpu)) && irqs > 1) {
                                pr_warn("unable to set irq affinity (irq=%d, cpu=%u)\n",
-                                       irq, i);
+                                       irq, cpu);
                                continue;
                        }
 
                        err = request_irq(irq, handler,
                                          IRQF_NOBALANCING | IRQF_NO_THREAD, "arm-pmu",
-                                         per_cpu_ptr(&hw_events->percpu_pmu, i));
+                                         per_cpu_ptr(&hw_events->percpu_pmu, cpu));
                        if (err) {
                                pr_err("unable to request IRQ%d for ARM PMU counters\n",
                                        irq);
                                return err;
                        }
 
-                       cpumask_set_cpu(i, &cpu_pmu->active_irqs);
+                       cpumask_set_cpu(cpu, &cpu_pmu->active_irqs);
                }
        }
 
@@ -243,6 +253,8 @@ static const struct of_device_id cpu_pmu_of_device_ids[] = {
        {.compatible = "arm,arm1176-pmu",       .data = armv6_1176_pmu_init},
        {.compatible = "arm,arm1136-pmu",       .data = armv6_1136_pmu_init},
        {.compatible = "qcom,krait-pmu",        .data = krait_pmu_init},
+       {.compatible = "qcom,scorpion-pmu",     .data = scorpion_pmu_init},
+       {.compatible = "qcom,scorpion-mp-pmu",  .data = scorpion_mp_pmu_init},
        {},
 };
 
@@ -289,6 +301,48 @@ static int probe_current_pmu(struct arm_pmu *pmu)
        return ret;
 }
 
+static int of_pmu_irq_cfg(struct platform_device *pdev)
+{
+       int i;
+       int *irqs = kcalloc(pdev->num_resources, sizeof(*irqs), GFP_KERNEL);
+
+       if (!irqs)
+               return -ENOMEM;
+
+       for (i = 0; i < pdev->num_resources; ++i) {
+               struct device_node *dn;
+               int cpu;
+
+               dn = of_parse_phandle(pdev->dev.of_node, "interrupt-affinity",
+                                     i);
+               if (!dn) {
+                       pr_warn("Failed to parse %s/interrupt-affinity[%d]\n",
+                               of_node_full_name(dn), i);
+                       break;
+               }
+
+               for_each_possible_cpu(cpu)
+                       if (arch_find_n_match_cpu_physical_id(dn, cpu, NULL))
+                               break;
+
+               of_node_put(dn);
+               if (cpu >= nr_cpu_ids) {
+                       pr_warn("Failed to find logical CPU for %s\n",
+                               dn->name);
+                       break;
+               }
+
+               irqs[i] = cpu;
+       }
+
+       if (i == pdev->num_resources)
+               cpu_pmu->irq_affinity = irqs;
+       else
+               kfree(irqs);
+
+       return 0;
+}
+
 static int cpu_pmu_device_probe(struct platform_device *pdev)
 {
        const struct of_device_id *of_id;
@@ -313,7 +367,10 @@ static int cpu_pmu_device_probe(struct platform_device *pdev)
 
        if (node && (of_id = of_match_node(cpu_pmu_of_device_ids, pdev->dev.of_node))) {
                init_fn = of_id->data;
-               ret = init_fn(pmu);
+
+               ret = of_pmu_irq_cfg(pdev);
+               if (!ret)
+                       ret = init_fn(pmu);
        } else {
                ret = probe_current_pmu(pmu);
        }
index 8993770c47de7ebdb59e5151bf2c4bc7948e19fd..f4207a4dcb013ca4b19b42e3d3c2b5ec9d620fde 100644 (file)
@@ -140,6 +140,23 @@ enum krait_perf_types {
        KRAIT_PERFCTR_L1_DTLB_ACCESS                    = 0x12210,
 };
 
+/* ARMv7 Scorpion specific event types */
+enum scorpion_perf_types {
+       SCORPION_LPM0_GROUP0                            = 0x4c,
+       SCORPION_LPM1_GROUP0                            = 0x50,
+       SCORPION_LPM2_GROUP0                            = 0x54,
+       SCORPION_L2LPM_GROUP0                           = 0x58,
+       SCORPION_VLPM_GROUP0                            = 0x5c,
+
+       SCORPION_ICACHE_ACCESS                          = 0x10053,
+       SCORPION_ICACHE_MISS                            = 0x10052,
+
+       SCORPION_DTLB_ACCESS                            = 0x12013,
+       SCORPION_DTLB_MISS                              = 0x12012,
+
+       SCORPION_ITLB_MISS                              = 0x12021,
+};
+
 /*
  * Cortex-A8 HW events mapping
  *
@@ -481,6 +498,49 @@ static const unsigned krait_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
        [C(BPU)][C(OP_WRITE)][C(RESULT_MISS)]   = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED,
 };
 
+/*
+ * Scorpion HW events mapping
+ */
+static const unsigned scorpion_perf_map[PERF_COUNT_HW_MAX] = {
+       PERF_MAP_ALL_UNSUPPORTED,
+       [PERF_COUNT_HW_CPU_CYCLES]          = ARMV7_PERFCTR_CPU_CYCLES,
+       [PERF_COUNT_HW_INSTRUCTIONS]        = ARMV7_PERFCTR_INSTR_EXECUTED,
+       [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_CLOCK_CYCLES,
+};
+
+static const unsigned scorpion_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
+                                           [PERF_COUNT_HW_CACHE_OP_MAX]
+                                           [PERF_COUNT_HW_CACHE_RESULT_MAX] = {
+       PERF_CACHE_MAP_ALL_UNSUPPORTED,
+       /*
+        * 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(L1D)][C(OP_READ)][C(RESULT_ACCESS)] = ARMV7_PERFCTR_L1_DCACHE_ACCESS,
+       [C(L1D)][C(OP_READ)][C(RESULT_MISS)] = ARMV7_PERFCTR_L1_DCACHE_REFILL,
+       [C(L1D)][C(OP_WRITE)][C(RESULT_ACCESS)] = ARMV7_PERFCTR_L1_DCACHE_ACCESS,
+       [C(L1D)][C(OP_WRITE)][C(RESULT_MISS)] = ARMV7_PERFCTR_L1_DCACHE_REFILL,
+       [C(L1I)][C(OP_READ)][C(RESULT_ACCESS)] = SCORPION_ICACHE_ACCESS,
+       [C(L1I)][C(OP_READ)][C(RESULT_MISS)] = SCORPION_ICACHE_MISS,
+       /*
+        * Only ITLB misses and DTLB refills are supported.  If users want the
+        * DTLB refills misses a raw counter must be used.
+        */
+       [C(DTLB)][C(OP_READ)][C(RESULT_ACCESS)] = SCORPION_DTLB_ACCESS,
+       [C(DTLB)][C(OP_READ)][C(RESULT_MISS)] = SCORPION_DTLB_MISS,
+       [C(DTLB)][C(OP_WRITE)][C(RESULT_ACCESS)] = SCORPION_DTLB_ACCESS,
+       [C(DTLB)][C(OP_WRITE)][C(RESULT_MISS)] = SCORPION_DTLB_MISS,
+       [C(ITLB)][C(OP_READ)][C(RESULT_MISS)] = SCORPION_ITLB_MISS,
+       [C(ITLB)][C(OP_WRITE)][C(RESULT_MISS)] = SCORPION_ITLB_MISS,
+       [C(BPU)][C(OP_READ)][C(RESULT_ACCESS)] = ARMV7_PERFCTR_PC_BRANCH_PRED,
+       [C(BPU)][C(OP_READ)][C(RESULT_MISS)] = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED,
+       [C(BPU)][C(OP_WRITE)][C(RESULT_ACCESS)] = ARMV7_PERFCTR_PC_BRANCH_PRED,
+       [C(BPU)][C(OP_WRITE)][C(RESULT_MISS)] = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED,
+};
+
 /*
  * Perf Events' indices
  */
@@ -976,6 +1036,12 @@ static int krait_map_event_no_branch(struct perf_event *event)
                                &krait_perf_cache_map, 0xFFFFF);
 }
 
+static int scorpion_map_event(struct perf_event *event)
+{
+       return armpmu_map_event(event, &scorpion_perf_map,
+                               &scorpion_perf_cache_map, 0xFFFFF);
+}
+
 static void armv7pmu_init(struct arm_pmu *cpu_pmu)
 {
        cpu_pmu->handle_irq     = armv7pmu_handle_irq;
@@ -1103,6 +1169,12 @@ static int armv7_a17_pmu_init(struct arm_pmu *cpu_pmu)
 #define KRAIT_EVENT_MASK       (KRAIT_EVENT | VENUM_EVENT)
 #define PMRESRn_EN             BIT(31)
 
+#define EVENT_REGION(event)    (((event) >> 12) & 0xf)         /* R */
+#define EVENT_GROUP(event)     ((event) & 0xf)                 /* G */
+#define EVENT_CODE(event)      (((event) >> 4) & 0xff)         /* CC */
+#define EVENT_VENUM(event)     (!!(event & VENUM_EVENT))       /* N=2 */
+#define EVENT_CPU(event)       (!!(event & KRAIT_EVENT))       /* N=1 */
+
 static u32 krait_read_pmresrn(int n)
 {
        u32 val;
@@ -1141,19 +1213,19 @@ static void krait_write_pmresrn(int n, u32 val)
        }
 }
 
-static u32 krait_read_vpmresr0(void)
+static u32 venum_read_pmresr(void)
 {
        u32 val;
        asm volatile("mrc p10, 7, %0, c11, c0, 0" : "=r" (val));
        return val;
 }
 
-static void krait_write_vpmresr0(u32 val)
+static void venum_write_pmresr(u32 val)
 {
        asm volatile("mcr p10, 7, %0, c11, c0, 0" : : "r" (val));
 }
 
-static void krait_pre_vpmresr0(u32 *venum_orig_val, u32 *fp_orig_val)
+static void venum_pre_pmresr(u32 *venum_orig_val, u32 *fp_orig_val)
 {
        u32 venum_new_val;
        u32 fp_new_val;
@@ -1170,7 +1242,7 @@ static void krait_pre_vpmresr0(u32 *venum_orig_val, u32 *fp_orig_val)
        fmxr(FPEXC, fp_new_val);
 }
 
-static void krait_post_vpmresr0(u32 venum_orig_val, u32 fp_orig_val)
+static void venum_post_pmresr(u32 venum_orig_val, u32 fp_orig_val)
 {
        BUG_ON(preemptible());
        /* Restore FPEXC */
@@ -1193,16 +1265,11 @@ static void krait_evt_setup(int idx, u32 config_base)
        u32 val;
        u32 mask;
        u32 vval, fval;
-       unsigned int region;
-       unsigned int group;
-       unsigned int code;
+       unsigned int region = EVENT_REGION(config_base);
+       unsigned int group = EVENT_GROUP(config_base);
+       unsigned int code = EVENT_CODE(config_base);
        unsigned int group_shift;
-       bool venum_event;
-
-       venum_event = !!(config_base & VENUM_EVENT);
-       region = (config_base >> 12) & 0xf;
-       code   = (config_base >> 4) & 0xff;
-       group  = (config_base >> 0)  & 0xf;
+       bool venum_event = EVENT_VENUM(config_base);
 
        group_shift = group * 8;
        mask = 0xff << group_shift;
@@ -1217,16 +1284,14 @@ static void krait_evt_setup(int idx, u32 config_base)
        val |= config_base & (ARMV7_EXCLUDE_USER | ARMV7_EXCLUDE_PL1);
        armv7_pmnc_write_evtsel(idx, val);
 
-       asm volatile("mcr p15, 0, %0, c9, c15, 0" : : "r" (0));
-
        if (venum_event) {
-               krait_pre_vpmresr0(&vval, &fval);
-               val = krait_read_vpmresr0();
+               venum_pre_pmresr(&vval, &fval);
+               val = venum_read_pmresr();
                val &= ~mask;
                val |= code << group_shift;
                val |= PMRESRn_EN;
-               krait_write_vpmresr0(val);
-               krait_post_vpmresr0(vval, fval);
+               venum_write_pmresr(val);
+               venum_post_pmresr(vval, fval);
        } else {
                val = krait_read_pmresrn(region);
                val &= ~mask;
@@ -1236,7 +1301,7 @@ static void krait_evt_setup(int idx, u32 config_base)
        }
 }
 
-static u32 krait_clear_pmresrn_group(u32 val, int group)
+static u32 clear_pmresrn_group(u32 val, int group)
 {
        u32 mask;
        int group_shift;
@@ -1256,23 +1321,19 @@ static void krait_clearpmu(u32 config_base)
 {
        u32 val;
        u32 vval, fval;
-       unsigned int region;
-       unsigned int group;
-       bool venum_event;
-
-       venum_event = !!(config_base & VENUM_EVENT);
-       region = (config_base >> 12) & 0xf;
-       group  = (config_base >> 0)  & 0xf;
+       unsigned int region = EVENT_REGION(config_base);
+       unsigned int group = EVENT_GROUP(config_base);
+       bool venum_event = EVENT_VENUM(config_base);
 
        if (venum_event) {
-               krait_pre_vpmresr0(&vval, &fval);
-               val = krait_read_vpmresr0();
-               val = krait_clear_pmresrn_group(val, group);
-               krait_write_vpmresr0(val);
-               krait_post_vpmresr0(vval, fval);
+               venum_pre_pmresr(&vval, &fval);
+               val = venum_read_pmresr();
+               val = clear_pmresrn_group(val, group);
+               venum_write_pmresr(val);
+               venum_post_pmresr(vval, fval);
        } else {
                val = krait_read_pmresrn(region);
-               val = krait_clear_pmresrn_group(val, group);
+               val = clear_pmresrn_group(val, group);
                krait_write_pmresrn(region, val);
        }
 }
@@ -1342,6 +1403,8 @@ static void krait_pmu_enable_event(struct perf_event *event)
 static void krait_pmu_reset(void *info)
 {
        u32 vval, fval;
+       struct arm_pmu *cpu_pmu = info;
+       u32 idx, nb_cnt = cpu_pmu->num_events;
 
        armv7pmu_reset(info);
 
@@ -1350,9 +1413,16 @@ static void krait_pmu_reset(void *info)
        krait_write_pmresrn(1, 0);
        krait_write_pmresrn(2, 0);
 
-       krait_pre_vpmresr0(&vval, &fval);
-       krait_write_vpmresr0(0);
-       krait_post_vpmresr0(vval, fval);
+       venum_pre_pmresr(&vval, &fval);
+       venum_write_pmresr(0);
+       venum_post_pmresr(vval, fval);
+
+       /* Reset PMxEVNCTCR to sane default */
+       for (idx = ARMV7_IDX_CYCLE_COUNTER; idx < nb_cnt; ++idx) {
+               armv7_pmnc_select_counter(idx);
+               asm volatile("mcr p15, 0, %0, c9, c15, 0" : : "r" (0));
+       }
+
 }
 
 static int krait_event_to_bit(struct perf_event *event, unsigned int region,
@@ -1386,26 +1456,18 @@ static int krait_pmu_get_event_idx(struct pmu_hw_events *cpuc,
 {
        int idx;
        int bit = -1;
-       unsigned int prefix;
-       unsigned int region;
-       unsigned int code;
-       unsigned int group;
-       bool krait_event;
        struct hw_perf_event *hwc = &event->hw;
+       unsigned int region = EVENT_REGION(hwc->config_base);
+       unsigned int code = EVENT_CODE(hwc->config_base);
+       unsigned int group = EVENT_GROUP(hwc->config_base);
+       bool venum_event = EVENT_VENUM(hwc->config_base);
+       bool krait_event = EVENT_CPU(hwc->config_base);
 
-       region = (hwc->config_base >> 12) & 0xf;
-       code   = (hwc->config_base >> 4) & 0xff;
-       group  = (hwc->config_base >> 0) & 0xf;
-       krait_event = !!(hwc->config_base & KRAIT_EVENT_MASK);
-
-       if (krait_event) {
+       if (venum_event || krait_event) {
                /* Ignore invalid events */
                if (group > 3 || region > 2)
                        return -EINVAL;
-               prefix = hwc->config_base & KRAIT_EVENT_MASK;
-               if (prefix != KRAIT_EVENT && prefix != VENUM_EVENT)
-                       return -EINVAL;
-               if (prefix == VENUM_EVENT && (code & 0xe0))
+               if (venum_event && (code & 0xe0))
                        return -EINVAL;
 
                bit = krait_event_to_bit(event, region, group);
@@ -1425,15 +1487,12 @@ static void krait_pmu_clear_event_idx(struct pmu_hw_events *cpuc,
 {
        int bit;
        struct hw_perf_event *hwc = &event->hw;
-       unsigned int region;
-       unsigned int group;
-       bool krait_event;
+       unsigned int region = EVENT_REGION(hwc->config_base);
+       unsigned int group = EVENT_GROUP(hwc->config_base);
+       bool venum_event = EVENT_VENUM(hwc->config_base);
+       bool krait_event = EVENT_CPU(hwc->config_base);
 
-       region = (hwc->config_base >> 12) & 0xf;
-       group  = (hwc->config_base >> 0) & 0xf;
-       krait_event = !!(hwc->config_base & KRAIT_EVENT_MASK);
-
-       if (krait_event) {
+       if (venum_event || krait_event) {
                bit = krait_event_to_bit(event, region, group);
                clear_bit(bit, cpuc->used_mask);
        }
@@ -1458,6 +1517,344 @@ static int krait_pmu_init(struct arm_pmu *cpu_pmu)
        cpu_pmu->clear_event_idx = krait_pmu_clear_event_idx;
        return 0;
 }
+
+/*
+ * Scorpion Local Performance Monitor Register (LPMn)
+ *
+ *            31   30     24     16     8      0
+ *            +--------------------------------+
+ *  LPM0      | EN |  CC  |  CC  |  CC  |  CC  |   N = 1, R = 0
+ *            +--------------------------------+
+ *  LPM1      | EN |  CC  |  CC  |  CC  |  CC  |   N = 1, R = 1
+ *            +--------------------------------+
+ *  LPM2      | EN |  CC  |  CC  |  CC  |  CC  |   N = 1, R = 2
+ *            +--------------------------------+
+ *  L2LPM     | EN |  CC  |  CC  |  CC  |  CC  |   N = 1, R = 3
+ *            +--------------------------------+
+ *  VLPM      | EN |  CC  |  CC  |  CC  |  CC  |   N = 2, R = ?
+ *            +--------------------------------+
+ *              EN | G=3  | G=2  | G=1  | G=0
+ *
+ *
+ *  Event Encoding:
+ *
+ *      hwc->config_base = 0xNRCCG
+ *
+ *      N  = prefix, 1 for Scorpion CPU (LPMn/L2LPM), 2 for Venum VFP (VLPM)
+ *      R  = region register
+ *      CC = class of events the group G is choosing from
+ *      G  = group or particular event
+ *
+ *  Example: 0x12021 is a Scorpion CPU event in LPM2's group 1 with code 2
+ *
+ *  A region (R) corresponds to a piece of the CPU (execution unit, instruction
+ *  unit, etc.) while the event code (CC) corresponds to a particular class of
+ *  events (interrupts for example). An event code is broken down into
+ *  groups (G) that can be mapped into the PMU (irq, fiqs, and irq+fiqs for
+ *  example).
+ */
+
+static u32 scorpion_read_pmresrn(int n)
+{
+       u32 val;
+
+       switch (n) {
+       case 0:
+               asm volatile("mrc p15, 0, %0, c15, c0, 0" : "=r" (val));
+               break;
+       case 1:
+               asm volatile("mrc p15, 1, %0, c15, c0, 0" : "=r" (val));
+               break;
+       case 2:
+               asm volatile("mrc p15, 2, %0, c15, c0, 0" : "=r" (val));
+               break;
+       case 3:
+               asm volatile("mrc p15, 3, %0, c15, c2, 0" : "=r" (val));
+               break;
+       default:
+               BUG(); /* Should be validated in scorpion_pmu_get_event_idx() */
+       }
+
+       return val;
+}
+
+static void scorpion_write_pmresrn(int n, u32 val)
+{
+       switch (n) {
+       case 0:
+               asm volatile("mcr p15, 0, %0, c15, c0, 0" : : "r" (val));
+               break;
+       case 1:
+               asm volatile("mcr p15, 1, %0, c15, c0, 0" : : "r" (val));
+               break;
+       case 2:
+               asm volatile("mcr p15, 2, %0, c15, c0, 0" : : "r" (val));
+               break;
+       case 3:
+               asm volatile("mcr p15, 3, %0, c15, c2, 0" : : "r" (val));
+               break;
+       default:
+               BUG(); /* Should be validated in scorpion_pmu_get_event_idx() */
+       }
+}
+
+static u32 scorpion_get_pmresrn_event(unsigned int region)
+{
+       static const u32 pmresrn_table[] = { SCORPION_LPM0_GROUP0,
+                                            SCORPION_LPM1_GROUP0,
+                                            SCORPION_LPM2_GROUP0,
+                                            SCORPION_L2LPM_GROUP0 };
+       return pmresrn_table[region];
+}
+
+static void scorpion_evt_setup(int idx, u32 config_base)
+{
+       u32 val;
+       u32 mask;
+       u32 vval, fval;
+       unsigned int region = EVENT_REGION(config_base);
+       unsigned int group = EVENT_GROUP(config_base);
+       unsigned int code = EVENT_CODE(config_base);
+       unsigned int group_shift;
+       bool venum_event = EVENT_VENUM(config_base);
+
+       group_shift = group * 8;
+       mask = 0xff << group_shift;
+
+       /* Configure evtsel for the region and group */
+       if (venum_event)
+               val = SCORPION_VLPM_GROUP0;
+       else
+               val = scorpion_get_pmresrn_event(region);
+       val += group;
+       /* Mix in mode-exclusion bits */
+       val |= config_base & (ARMV7_EXCLUDE_USER | ARMV7_EXCLUDE_PL1);
+       armv7_pmnc_write_evtsel(idx, val);
+
+       asm volatile("mcr p15, 0, %0, c9, c15, 0" : : "r" (0));
+
+       if (venum_event) {
+               venum_pre_pmresr(&vval, &fval);
+               val = venum_read_pmresr();
+               val &= ~mask;
+               val |= code << group_shift;
+               val |= PMRESRn_EN;
+               venum_write_pmresr(val);
+               venum_post_pmresr(vval, fval);
+       } else {
+               val = scorpion_read_pmresrn(region);
+               val &= ~mask;
+               val |= code << group_shift;
+               val |= PMRESRn_EN;
+               scorpion_write_pmresrn(region, val);
+       }
+}
+
+static void scorpion_clearpmu(u32 config_base)
+{
+       u32 val;
+       u32 vval, fval;
+       unsigned int region = EVENT_REGION(config_base);
+       unsigned int group = EVENT_GROUP(config_base);
+       bool venum_event = EVENT_VENUM(config_base);
+
+       if (venum_event) {
+               venum_pre_pmresr(&vval, &fval);
+               val = venum_read_pmresr();
+               val = clear_pmresrn_group(val, group);
+               venum_write_pmresr(val);
+               venum_post_pmresr(vval, fval);
+       } else {
+               val = scorpion_read_pmresrn(region);
+               val = clear_pmresrn_group(val, group);
+               scorpion_write_pmresrn(region, val);
+       }
+}
+
+static void scorpion_pmu_disable_event(struct perf_event *event)
+{
+       unsigned long flags;
+       struct hw_perf_event *hwc = &event->hw;
+       int idx = hwc->idx;
+       struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu);
+       struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events);
+
+       /* Disable counter and interrupt */
+       raw_spin_lock_irqsave(&events->pmu_lock, flags);
+
+       /* Disable counter */
+       armv7_pmnc_disable_counter(idx);
+
+       /*
+        * Clear pmresr code (if destined for PMNx counters)
+        */
+       if (hwc->config_base & KRAIT_EVENT_MASK)
+               scorpion_clearpmu(hwc->config_base);
+
+       /* Disable interrupt for this counter */
+       armv7_pmnc_disable_intens(idx);
+
+       raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
+}
+
+static void scorpion_pmu_enable_event(struct perf_event *event)
+{
+       unsigned long flags;
+       struct hw_perf_event *hwc = &event->hw;
+       int idx = hwc->idx;
+       struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu);
+       struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events);
+
+       /*
+        * Enable counter and interrupt, and set the counter to count
+        * the event that we're interested in.
+        */
+       raw_spin_lock_irqsave(&events->pmu_lock, flags);
+
+       /* Disable counter */
+       armv7_pmnc_disable_counter(idx);
+
+       /*
+        * Set event (if destined for PMNx counters)
+        * We don't set the event for the cycle counter because we
+        * don't have the ability to perform event filtering.
+        */
+       if (hwc->config_base & KRAIT_EVENT_MASK)
+               scorpion_evt_setup(idx, hwc->config_base);
+       else if (idx != ARMV7_IDX_CYCLE_COUNTER)
+               armv7_pmnc_write_evtsel(idx, hwc->config_base);
+
+       /* Enable interrupt for this counter */
+       armv7_pmnc_enable_intens(idx);
+
+       /* Enable counter */
+       armv7_pmnc_enable_counter(idx);
+
+       raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
+}
+
+static void scorpion_pmu_reset(void *info)
+{
+       u32 vval, fval;
+       struct arm_pmu *cpu_pmu = info;
+       u32 idx, nb_cnt = cpu_pmu->num_events;
+
+       armv7pmu_reset(info);
+
+       /* Clear all pmresrs */
+       scorpion_write_pmresrn(0, 0);
+       scorpion_write_pmresrn(1, 0);
+       scorpion_write_pmresrn(2, 0);
+       scorpion_write_pmresrn(3, 0);
+
+       venum_pre_pmresr(&vval, &fval);
+       venum_write_pmresr(0);
+       venum_post_pmresr(vval, fval);
+
+       /* Reset PMxEVNCTCR to sane default */
+       for (idx = ARMV7_IDX_CYCLE_COUNTER; idx < nb_cnt; ++idx) {
+               armv7_pmnc_select_counter(idx);
+               asm volatile("mcr p15, 0, %0, c9, c15, 0" : : "r" (0));
+       }
+}
+
+static int scorpion_event_to_bit(struct perf_event *event, unsigned int region,
+                             unsigned int group)
+{
+       int bit;
+       struct hw_perf_event *hwc = &event->hw;
+       struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu);
+
+       if (hwc->config_base & VENUM_EVENT)
+               bit = SCORPION_VLPM_GROUP0;
+       else
+               bit = scorpion_get_pmresrn_event(region);
+       bit -= scorpion_get_pmresrn_event(0);
+       bit += group;
+       /*
+        * Lower bits are reserved for use by the counters (see
+        * armv7pmu_get_event_idx() for more info)
+        */
+       bit += ARMV7_IDX_COUNTER_LAST(cpu_pmu) + 1;
+
+       return bit;
+}
+
+/*
+ * We check for column exclusion constraints here.
+ * Two events cant use the same group within a pmresr register.
+ */
+static int scorpion_pmu_get_event_idx(struct pmu_hw_events *cpuc,
+                                  struct perf_event *event)
+{
+       int idx;
+       int bit = -1;
+       struct hw_perf_event *hwc = &event->hw;
+       unsigned int region = EVENT_REGION(hwc->config_base);
+       unsigned int group = EVENT_GROUP(hwc->config_base);
+       bool venum_event = EVENT_VENUM(hwc->config_base);
+       bool scorpion_event = EVENT_CPU(hwc->config_base);
+
+       if (venum_event || scorpion_event) {
+               /* Ignore invalid events */
+               if (group > 3 || region > 3)
+                       return -EINVAL;
+
+               bit = scorpion_event_to_bit(event, region, group);
+               if (test_and_set_bit(bit, cpuc->used_mask))
+                       return -EAGAIN;
+       }
+
+       idx = armv7pmu_get_event_idx(cpuc, event);
+       if (idx < 0 && bit >= 0)
+               clear_bit(bit, cpuc->used_mask);
+
+       return idx;
+}
+
+static void scorpion_pmu_clear_event_idx(struct pmu_hw_events *cpuc,
+                                     struct perf_event *event)
+{
+       int bit;
+       struct hw_perf_event *hwc = &event->hw;
+       unsigned int region = EVENT_REGION(hwc->config_base);
+       unsigned int group = EVENT_GROUP(hwc->config_base);
+       bool venum_event = EVENT_VENUM(hwc->config_base);
+       bool scorpion_event = EVENT_CPU(hwc->config_base);
+
+       if (venum_event || scorpion_event) {
+               bit = scorpion_event_to_bit(event, region, group);
+               clear_bit(bit, cpuc->used_mask);
+       }
+}
+
+static int scorpion_pmu_init(struct arm_pmu *cpu_pmu)
+{
+       armv7pmu_init(cpu_pmu);
+       cpu_pmu->name           = "armv7_scorpion";
+       cpu_pmu->map_event      = scorpion_map_event;
+       cpu_pmu->num_events     = armv7_read_num_pmnc_events();
+       cpu_pmu->reset          = scorpion_pmu_reset;
+       cpu_pmu->enable         = scorpion_pmu_enable_event;
+       cpu_pmu->disable        = scorpion_pmu_disable_event;
+       cpu_pmu->get_event_idx  = scorpion_pmu_get_event_idx;
+       cpu_pmu->clear_event_idx = scorpion_pmu_clear_event_idx;
+       return 0;
+}
+
+static int scorpion_mp_pmu_init(struct arm_pmu *cpu_pmu)
+{
+       armv7pmu_init(cpu_pmu);
+       cpu_pmu->name           = "armv7_scorpion_mp";
+       cpu_pmu->map_event      = scorpion_map_event;
+       cpu_pmu->num_events     = armv7_read_num_pmnc_events();
+       cpu_pmu->reset          = scorpion_pmu_reset;
+       cpu_pmu->enable         = scorpion_pmu_enable_event;
+       cpu_pmu->disable        = scorpion_pmu_disable_event;
+       cpu_pmu->get_event_idx  = scorpion_pmu_get_event_idx;
+       cpu_pmu->clear_event_idx = scorpion_pmu_clear_event_idx;
+       return 0;
+}
 #else
 static inline int armv7_a8_pmu_init(struct arm_pmu *cpu_pmu)
 {
@@ -1498,4 +1895,14 @@ static inline int krait_pmu_init(struct arm_pmu *cpu_pmu)
 {
        return -ENODEV;
 }
+
+static inline int scorpion_pmu_init(struct arm_pmu *cpu_pmu)
+{
+       return -ENODEV;
+}
+
+static inline int scorpion_mp_pmu_init(struct arm_pmu *cpu_pmu)
+{
+       return -ENODEV;
+}
 #endif /* CONFIG_CPU_V7 */
index fdfa3a78ec8cb8d7c96098f58175eea28e8a6da5..f192a2a4171935720cfc702953703c78078579cc 100644 (file)
 #include <linux/stddef.h>
 #include <linux/unistd.h>
 #include <linux/user.h>
-#include <linux/delay.h>
-#include <linux/reboot.h>
 #include <linux/interrupt.h>
 #include <linux/kallsyms.h>
 #include <linux/init.h>
-#include <linux/cpu.h>
 #include <linux/elfcore.h>
 #include <linux/pm.h>
 #include <linux/tick.h>
 #include <linux/random.h>
 #include <linux/hw_breakpoint.h>
 #include <linux/leds.h>
-#include <linux/reboot.h>
 
-#include <asm/cacheflush.h>
-#include <asm/idmap.h>
 #include <asm/processor.h>
 #include <asm/thread_notify.h>
 #include <asm/stacktrace.h>
 #include <asm/system_misc.h>
 #include <asm/mach/time.h>
 #include <asm/tls.h>
+#include <asm/vdso.h>
 
 #ifdef CONFIG_CC_STACKPROTECTOR
 #include <linux/stackprotector.h>
@@ -59,69 +54,6 @@ static const char *isa_modes[] __maybe_unused = {
   "ARM" , "Thumb" , "Jazelle", "ThumbEE"
 };
 
-extern void call_with_stack(void (*fn)(void *), void *arg, void *sp);
-typedef void (*phys_reset_t)(unsigned long);
-
-/*
- * A temporary stack to use for CPU reset. This is static so that we
- * don't clobber it with the identity mapping. When running with this
- * stack, any references to the current task *will not work* so you
- * should really do as little as possible before jumping to your reset
- * code.
- */
-static u64 soft_restart_stack[16];
-
-static void __soft_restart(void *addr)
-{
-       phys_reset_t phys_reset;
-
-       /* Take out a flat memory mapping. */
-       setup_mm_for_reboot();
-
-       /* Clean and invalidate caches */
-       flush_cache_all();
-
-       /* Turn off caching */
-       cpu_proc_fin();
-
-       /* Push out any further dirty data, and ensure cache is empty */
-       flush_cache_all();
-
-       /* Switch to the identity mapping. */
-       phys_reset = (phys_reset_t)(unsigned long)virt_to_phys(cpu_reset);
-       phys_reset((unsigned long)addr);
-
-       /* Should never get here. */
-       BUG();
-}
-
-void soft_restart(unsigned long addr)
-{
-       u64 *stack = soft_restart_stack + ARRAY_SIZE(soft_restart_stack);
-
-       /* Disable interrupts first */
-       raw_local_irq_disable();
-       local_fiq_disable();
-
-       /* Disable the L2 if we're the last man standing. */
-       if (num_online_cpus() == 1)
-               outer_disable();
-
-       /* Change to the new stack and continue with the reset. */
-       call_with_stack(__soft_restart, (void *)addr, (void *)stack);
-
-       /* Should never get here. */
-       BUG();
-}
-
-/*
- * Function pointers to optional machine specific functions
- */
-void (*pm_power_off)(void);
-EXPORT_SYMBOL(pm_power_off);
-
-void (*arm_pm_restart)(enum reboot_mode reboot_mode, const char *cmd);
-
 /*
  * This is our default idle handler.
  */
@@ -166,79 +98,6 @@ void arch_cpu_idle_dead(void)
 }
 #endif
 
-/*
- * Called by kexec, immediately prior to machine_kexec().
- *
- * This must completely disable all secondary CPUs; simply causing those CPUs
- * to execute e.g. a RAM-based pin loop is not sufficient. This allows the
- * kexec'd kernel to use any and all RAM as it sees fit, without having to
- * avoid any code or data used by any SW CPU pin loop. The CPU hotplug
- * functionality embodied in disable_nonboot_cpus() to achieve this.
- */
-void machine_shutdown(void)
-{
-       disable_nonboot_cpus();
-}
-
-/*
- * Halting simply requires that the secondary CPUs stop performing any
- * activity (executing tasks, handling interrupts). smp_send_stop()
- * achieves this.
- */
-void machine_halt(void)
-{
-       local_irq_disable();
-       smp_send_stop();
-
-       local_irq_disable();
-       while (1);
-}
-
-/*
- * Power-off simply requires that the secondary CPUs stop performing any
- * activity (executing tasks, handling interrupts). smp_send_stop()
- * achieves this. When the system power is turned off, it will take all CPUs
- * with it.
- */
-void machine_power_off(void)
-{
-       local_irq_disable();
-       smp_send_stop();
-
-       if (pm_power_off)
-               pm_power_off();
-}
-
-/*
- * Restart requires that the secondary CPUs stop performing any activity
- * while the primary CPU resets the system. Systems with a single CPU can
- * use soft_restart() as their machine descriptor's .restart hook, since that
- * will cause the only available CPU to reset. Systems with multiple CPUs must
- * provide a HW restart implementation, to ensure that all CPUs reset at once.
- * This is required so that any code running after reset on the primary CPU
- * doesn't have to co-ordinate with other CPUs to ensure they aren't still
- * executing pre-reset code, and using RAM that the primary CPU's code wishes
- * to use. Implementing such co-ordination would be essentially impossible.
- */
-void machine_restart(char *cmd)
-{
-       local_irq_disable();
-       smp_send_stop();
-
-       if (arm_pm_restart)
-               arm_pm_restart(reboot_mode, cmd);
-       else
-               do_kernel_restart(cmd);
-
-       /* Give a grace period for failure to restart of 1s */
-       mdelay(1000);
-
-       /* Whoops - the platform was unable to reboot. Tell the user! */
-       printk("Reboot failed -- System halted\n");
-       local_irq_disable();
-       while (1);
-}
-
 void __show_regs(struct pt_regs *regs)
 {
        unsigned long flags;
@@ -475,7 +334,7 @@ const char *arch_vma_name(struct vm_area_struct *vma)
 }
 
 /* If possible, provide a placement hint at a random offset from the
- * stack for the signal page.
+ * stack for the sigpage and vdso pages.
  */
 static unsigned long sigpage_addr(const struct mm_struct *mm,
                                  unsigned int npages)
@@ -519,6 +378,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
 {
        struct mm_struct *mm = current->mm;
        struct vm_area_struct *vma;
+       unsigned long npages;
        unsigned long addr;
        unsigned long hint;
        int ret = 0;
@@ -528,9 +388,12 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
        if (!signal_page)
                return -ENOMEM;
 
+       npages = 1; /* for sigpage */
+       npages += vdso_total_pages;
+
        down_write(&mm->mmap_sem);
-       hint = sigpage_addr(mm, 1);
-       addr = get_unmapped_area(NULL, hint, PAGE_SIZE, 0, 0);
+       hint = sigpage_addr(mm, npages);
+       addr = get_unmapped_area(NULL, hint, npages << PAGE_SHIFT, 0, 0);
        if (IS_ERR_VALUE(addr)) {
                ret = addr;
                goto up_fail;
@@ -547,6 +410,12 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
 
        mm->context.sigpage = addr;
 
+       /* Unlike the sigpage, failure to install the vdso is unlikely
+        * to be fatal to the process, so no error check needed
+        * here.
+        */
+       arm_install_vdso(mm, addr + PAGE_SIZE);
+
  up_fail:
        up_write(&mm->mmap_sem);
        return ret;
diff --git a/arch/arm/kernel/psci-call.S b/arch/arm/kernel/psci-call.S
new file mode 100644 (file)
index 0000000..a78e9e1
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * Copyright (C) 2015 ARM Limited
+ *
+ * Author: Mark Rutland <mark.rutland@arm.com>
+ */
+
+#include <linux/linkage.h>
+
+#include <asm/opcodes-sec.h>
+#include <asm/opcodes-virt.h>
+
+/* int __invoke_psci_fn_hvc(u32 function_id, u32 arg0, u32 arg1, u32 arg2) */
+ENTRY(__invoke_psci_fn_hvc)
+       __HVC(0)
+       bx      lr
+ENDPROC(__invoke_psci_fn_hvc)
+
+/* int __invoke_psci_fn_smc(u32 function_id, u32 arg0, u32 arg1, u32 arg2) */
+ENTRY(__invoke_psci_fn_smc)
+       __SMC(0)
+       bx      lr
+ENDPROC(__invoke_psci_fn_smc)
index f73891b6b7300dc67e353a8694a035e9a212c2d7..f90fdf4ce7c7230c4f3e75da030ca7218bb7845f 100644 (file)
@@ -23,8 +23,6 @@
 
 #include <asm/compiler.h>
 #include <asm/errno.h>
-#include <asm/opcodes-sec.h>
-#include <asm/opcodes-virt.h>
 #include <asm/psci.h>
 #include <asm/system_misc.h>
 
@@ -33,6 +31,9 @@ struct psci_operations psci_ops;
 static int (*invoke_psci_fn)(u32, u32, u32, u32);
 typedef int (*psci_initcall_t)(const struct device_node *);
 
+asmlinkage int __invoke_psci_fn_hvc(u32, u32, u32, u32);
+asmlinkage int __invoke_psci_fn_smc(u32, u32, u32, u32);
+
 enum psci_function {
        PSCI_FN_CPU_SUSPEND,
        PSCI_FN_CPU_ON,
@@ -71,40 +72,6 @@ static u32 psci_power_state_pack(struct psci_power_state state)
                 & PSCI_0_2_POWER_STATE_AFFL_MASK);
 }
 
-/*
- * The following two functions are invoked via the invoke_psci_fn pointer
- * and will not be inlined, allowing us to piggyback on the AAPCS.
- */
-static noinline int __invoke_psci_fn_hvc(u32 function_id, u32 arg0, u32 arg1,
-                                        u32 arg2)
-{
-       asm volatile(
-                       __asmeq("%0", "r0")
-                       __asmeq("%1", "r1")
-                       __asmeq("%2", "r2")
-                       __asmeq("%3", "r3")
-                       __HVC(0)
-               : "+r" (function_id)
-               : "r" (arg0), "r" (arg1), "r" (arg2));
-
-       return function_id;
-}
-
-static noinline int __invoke_psci_fn_smc(u32 function_id, u32 arg0, u32 arg1,
-                                        u32 arg2)
-{
-       asm volatile(
-                       __asmeq("%0", "r0")
-                       __asmeq("%1", "r1")
-                       __asmeq("%2", "r2")
-                       __asmeq("%3", "r3")
-                       __SMC(0)
-               : "+r" (function_id)
-               : "r" (arg0), "r" (arg1), "r" (arg2));
-
-       return function_id;
-}
-
 static int psci_get_version(void)
 {
        int err;
diff --git a/arch/arm/kernel/reboot.c b/arch/arm/kernel/reboot.c
new file mode 100644 (file)
index 0000000..1a4d232
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ *  Copyright (C) 1996-2000 Russell King - Converted to ARM.
+ *  Original Copyright (C) 1995  Linus Torvalds
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/cpu.h>
+#include <linux/delay.h>
+#include <linux/reboot.h>
+
+#include <asm/cacheflush.h>
+#include <asm/idmap.h>
+
+#include "reboot.h"
+
+typedef void (*phys_reset_t)(unsigned long);
+
+/*
+ * Function pointers to optional machine specific functions
+ */
+void (*arm_pm_restart)(enum reboot_mode reboot_mode, const char *cmd);
+void (*pm_power_off)(void);
+EXPORT_SYMBOL(pm_power_off);
+
+/*
+ * A temporary stack to use for CPU reset. This is static so that we
+ * don't clobber it with the identity mapping. When running with this
+ * stack, any references to the current task *will not work* so you
+ * should really do as little as possible before jumping to your reset
+ * code.
+ */
+static u64 soft_restart_stack[16];
+
+static void __soft_restart(void *addr)
+{
+       phys_reset_t phys_reset;
+
+       /* Take out a flat memory mapping. */
+       setup_mm_for_reboot();
+
+       /* Clean and invalidate caches */
+       flush_cache_all();
+
+       /* Turn off caching */
+       cpu_proc_fin();
+
+       /* Push out any further dirty data, and ensure cache is empty */
+       flush_cache_all();
+
+       /* Switch to the identity mapping. */
+       phys_reset = (phys_reset_t)(unsigned long)virt_to_phys(cpu_reset);
+       phys_reset((unsigned long)addr);
+
+       /* Should never get here. */
+       BUG();
+}
+
+void _soft_restart(unsigned long addr, bool disable_l2)
+{
+       u64 *stack = soft_restart_stack + ARRAY_SIZE(soft_restart_stack);
+
+       /* Disable interrupts first */
+       raw_local_irq_disable();
+       local_fiq_disable();
+
+       /* Disable the L2 if we're the last man standing. */
+       if (disable_l2)
+               outer_disable();
+
+       /* Change to the new stack and continue with the reset. */
+       call_with_stack(__soft_restart, (void *)addr, (void *)stack);
+
+       /* Should never get here. */
+       BUG();
+}
+
+void soft_restart(unsigned long addr)
+{
+       _soft_restart(addr, num_online_cpus() == 1);
+}
+
+/*
+ * Called by kexec, immediately prior to machine_kexec().
+ *
+ * This must completely disable all secondary CPUs; simply causing those CPUs
+ * to execute e.g. a RAM-based pin loop is not sufficient. This allows the
+ * kexec'd kernel to use any and all RAM as it sees fit, without having to
+ * avoid any code or data used by any SW CPU pin loop. The CPU hotplug
+ * functionality embodied in disable_nonboot_cpus() to achieve this.
+ */
+void machine_shutdown(void)
+{
+       disable_nonboot_cpus();
+}
+
+/*
+ * Halting simply requires that the secondary CPUs stop performing any
+ * activity (executing tasks, handling interrupts). smp_send_stop()
+ * achieves this.
+ */
+void machine_halt(void)
+{
+       local_irq_disable();
+       smp_send_stop();
+
+       local_irq_disable();
+       while (1);
+}
+
+/*
+ * Power-off simply requires that the secondary CPUs stop performing any
+ * activity (executing tasks, handling interrupts). smp_send_stop()
+ * achieves this. When the system power is turned off, it will take all CPUs
+ * with it.
+ */
+void machine_power_off(void)
+{
+       local_irq_disable();
+       smp_send_stop();
+
+       if (pm_power_off)
+               pm_power_off();
+}
+
+/*
+ * Restart requires that the secondary CPUs stop performing any activity
+ * while the primary CPU resets the system. Systems with a single CPU can
+ * use soft_restart() as their machine descriptor's .restart hook, since that
+ * will cause the only available CPU to reset. Systems with multiple CPUs must
+ * provide a HW restart implementation, to ensure that all CPUs reset at once.
+ * This is required so that any code running after reset on the primary CPU
+ * doesn't have to co-ordinate with other CPUs to ensure they aren't still
+ * executing pre-reset code, and using RAM that the primary CPU's code wishes
+ * to use. Implementing such co-ordination would be essentially impossible.
+ */
+void machine_restart(char *cmd)
+{
+       local_irq_disable();
+       smp_send_stop();
+
+       if (arm_pm_restart)
+               arm_pm_restart(reboot_mode, cmd);
+       else
+               do_kernel_restart(cmd);
+
+       /* Give a grace period for failure to restart of 1s */
+       mdelay(1000);
+
+       /* Whoops - the platform was unable to reboot. Tell the user! */
+       printk("Reboot failed -- System halted\n");
+       local_irq_disable();
+       while (1);
+}
diff --git a/arch/arm/kernel/reboot.h b/arch/arm/kernel/reboot.h
new file mode 100644 (file)
index 0000000..bf7a0b1
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef REBOOT_H
+#define REBOOT_H
+
+extern void call_with_stack(void (*fn)(void *), void *arg, void *sp);
+extern void _soft_restart(unsigned long addr, bool disable_l2);
+
+#endif
index 24b4a04846ebe749c3ce5ec4fc2b82a9961c2a5f..36ed35073289b4af2c3053abfeb9e4bcb892c2b4 100644 (file)
@@ -56,8 +56,6 @@ void *return_address(unsigned int level)
                return NULL;
 }
 
-#else /* if defined(CONFIG_FRAME_POINTER) && !defined(CONFIG_ARM_UNWIND) */
-
-#endif /* if defined(CONFIG_FRAME_POINTER) && !defined(CONFIG_ARM_UNWIND) / else */
+#endif /* if defined(CONFIG_FRAME_POINTER) && !defined(CONFIG_ARM_UNWIND) */
 
 EXPORT_SYMBOL_GPL(return_address);
index 1d60bebea4b8b7923748cd6eb2d25fc4299bfc32..6c777e908a2446020b1fc88294ace488fb6098f3 100644 (file)
@@ -372,30 +372,48 @@ void __init early_print(const char *str, ...)
 
 static void __init cpuid_init_hwcaps(void)
 {
-       unsigned int divide_instrs, vmsa;
+       int block;
+       u32 isar5;
 
        if (cpu_architecture() < CPU_ARCH_ARMv7)
                return;
 
-       divide_instrs = (read_cpuid_ext(CPUID_EXT_ISAR0) & 0x0f000000) >> 24;
-
-       switch (divide_instrs) {
-       case 2:
+       block = cpuid_feature_extract(CPUID_EXT_ISAR0, 24);
+       if (block >= 2)
                elf_hwcap |= HWCAP_IDIVA;
-       case 1:
+       if (block >= 1)
                elf_hwcap |= HWCAP_IDIVT;
-       }
 
        /* LPAE implies atomic ldrd/strd instructions */
-       vmsa = (read_cpuid_ext(CPUID_EXT_MMFR0) & 0xf) >> 0;
-       if (vmsa >= 5)
+       block = cpuid_feature_extract(CPUID_EXT_MMFR0, 0);
+       if (block >= 5)
                elf_hwcap |= HWCAP_LPAE;
+
+       /* check for supported v8 Crypto instructions */
+       isar5 = read_cpuid_ext(CPUID_EXT_ISAR5);
+
+       block = cpuid_feature_extract_field(isar5, 4);
+       if (block >= 2)
+               elf_hwcap2 |= HWCAP2_PMULL;
+       if (block >= 1)
+               elf_hwcap2 |= HWCAP2_AES;
+
+       block = cpuid_feature_extract_field(isar5, 8);
+       if (block >= 1)
+               elf_hwcap2 |= HWCAP2_SHA1;
+
+       block = cpuid_feature_extract_field(isar5, 12);
+       if (block >= 1)
+               elf_hwcap2 |= HWCAP2_SHA2;
+
+       block = cpuid_feature_extract_field(isar5, 16);
+       if (block >= 1)
+               elf_hwcap2 |= HWCAP2_CRC32;
 }
 
 static void __init elf_hwcap_fixup(void)
 {
        unsigned id = read_cpuid_id();
-       unsigned sync_prim;
 
        /*
         * HWCAP_TLS is available only on 1136 r1p0 and later,
@@ -416,9 +434,9 @@ static void __init elf_hwcap_fixup(void)
         * avoid advertising SWP; it may not be atomic with
         * multiprocessing cores.
         */
-       sync_prim = ((read_cpuid_ext(CPUID_EXT_ISAR3) >> 8) & 0xf0) |
-                   ((read_cpuid_ext(CPUID_EXT_ISAR4) >> 20) & 0x0f);
-       if (sync_prim >= 0x13)
+       if (cpuid_feature_extract(CPUID_EXT_ISAR3, 12) > 1 ||
+           (cpuid_feature_extract(CPUID_EXT_ISAR3, 12) == 1 &&
+            cpuid_feature_extract(CPUID_EXT_ISAR3, 20) >= 3))
                elf_hwcap &= ~HWCAP_SWP;
 }
 
index e1e60e5a7a271eee56d34a69e55111b3ce0daf2d..7d37bfc508306b52a735f2de8d5c27d795bb6fa3 100644 (file)
@@ -116,14 +116,7 @@ cpu_resume_after_mmu:
        ldmfd   sp!, {r4 - r11, pc}
 ENDPROC(cpu_resume_after_mmu)
 
-/*
- * Note: Yes, part of the following code is located into the .data section.
- *       This is to allow sleep_save_sp to be accessed with a relative load
- *       while we can't rely on any MMU translation.  We could have put
- *       sleep_save_sp in the .text section as well, but some setups might
- *       insist on it to be truly read-only.
- */
-       .data
+       .text
        .align
 ENTRY(cpu_resume)
 ARM_BE8(setend be)                     @ ensure we are in BE mode
@@ -145,6 +138,8 @@ ARM_BE8(setend be)                  @ ensure we are in BE mode
        compute_mpidr_hash      r1, r4, r5, r6, r0, r3
 1:
        adr     r0, _sleep_save_sp
+       ldr     r2, [r0]
+       add     r0, r0, r2
        ldr     r0, [r0, #SLEEP_SAVE_SP_PHYS]
        ldr     r0, [r0, r1, lsl #2]
 
@@ -156,10 +151,12 @@ THUMB(    bx      r3                      )
 ENDPROC(cpu_resume)
 
        .align 2
+_sleep_save_sp:
+       .long   sleep_save_sp - .
 mpidr_hash_ptr:
        .long   mpidr_hash - .                  @ mpidr_hash struct offset
 
+       .data
        .type   sleep_save_sp, #object
 ENTRY(sleep_save_sp)
-_sleep_save_sp:
        .space  SLEEP_SAVE_SP_SZ                @ struct sleep_save_sp
index 86ef244c5a24b4fa80b20da26c5d522832a61d59..cca5b87581855244deba92fc78f2f0ae02b2ad07 100644 (file)
@@ -145,6 +145,11 @@ void __init smp_init_cpus(void)
                smp_ops.smp_init_cpus();
 }
 
+int platform_can_secondary_boot(void)
+{
+       return !!smp_ops.smp_boot_secondary;
+}
+
 int platform_can_cpu_hotplug(void)
 {
 #ifdef CONFIG_HOTPLUG_CPU
index afdd51e30bec073fd1efc5c1b65e104c8c89ea2d..1361756782c73b49c499f50bc4f423647e2edd3f 100644 (file)
@@ -42,7 +42,7 @@
        "       cmp             %0, #0\n"                       \
        "       movne           %0, %4\n"                       \
        "2:\n"                                                  \
-       "       .section         .fixup,\"ax\"\n"               \
+       "       .section         .text.fixup,\"ax\"\n"          \
        "       .align          2\n"                            \
        "3:     mov             %0, %5\n"                       \
        "       b               2b\n"                           \
diff --git a/arch/arm/kernel/vdso.c b/arch/arm/kernel/vdso.c
new file mode 100644 (file)
index 0000000..0d31d3c
--- /dev/null
@@ -0,0 +1,337 @@
+/*
+ * Adapted from arm64 version.
+ *
+ * Copyright (C) 2012 ARM Limited
+ * Copyright (C) 2015 Mentor Graphics Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/elf.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/of.h>
+#include <linux/printk.h>
+#include <linux/slab.h>
+#include <linux/timekeeper_internal.h>
+#include <linux/vmalloc.h>
+#include <asm/arch_timer.h>
+#include <asm/barrier.h>
+#include <asm/cacheflush.h>
+#include <asm/page.h>
+#include <asm/vdso.h>
+#include <asm/vdso_datapage.h>
+#include <clocksource/arm_arch_timer.h>
+
+#define MAX_SYMNAME    64
+
+static struct page **vdso_text_pagelist;
+
+/* Total number of pages needed for the data and text portions of the VDSO. */
+unsigned int vdso_total_pages __read_mostly;
+
+/*
+ * The VDSO data page.
+ */
+static union vdso_data_store vdso_data_store __page_aligned_data;
+static struct vdso_data *vdso_data = &vdso_data_store.data;
+
+static struct page *vdso_data_page;
+static struct vm_special_mapping vdso_data_mapping = {
+       .name = "[vvar]",
+       .pages = &vdso_data_page,
+};
+
+static struct vm_special_mapping vdso_text_mapping = {
+       .name = "[vdso]",
+};
+
+struct elfinfo {
+       Elf32_Ehdr      *hdr;           /* ptr to ELF */
+       Elf32_Sym       *dynsym;        /* ptr to .dynsym section */
+       unsigned long   dynsymsize;     /* size of .dynsym section */
+       char            *dynstr;        /* ptr to .dynstr section */
+};
+
+/* Cached result of boot-time check for whether the arch timer exists,
+ * and if so, whether the virtual counter is useable.
+ */
+static bool cntvct_ok __read_mostly;
+
+static bool __init cntvct_functional(void)
+{
+       struct device_node *np;
+       bool ret = false;
+
+       if (!IS_ENABLED(CONFIG_ARM_ARCH_TIMER))
+               goto out;
+
+       /* The arm_arch_timer core should export
+        * arch_timer_use_virtual or similar so we don't have to do
+        * this.
+        */
+       np = of_find_compatible_node(NULL, NULL, "arm,armv7-timer");
+       if (!np)
+               goto out_put;
+
+       if (of_property_read_bool(np, "arm,cpu-registers-not-fw-configured"))
+               goto out_put;
+
+       ret = true;
+
+out_put:
+       of_node_put(np);
+out:
+       return ret;
+}
+
+static void * __init find_section(Elf32_Ehdr *ehdr, const char *name,
+                                 unsigned long *size)
+{
+       Elf32_Shdr *sechdrs;
+       unsigned int i;
+       char *secnames;
+
+       /* Grab section headers and strings so we can tell who is who */
+       sechdrs = (void *)ehdr + ehdr->e_shoff;
+       secnames = (void *)ehdr + sechdrs[ehdr->e_shstrndx].sh_offset;
+
+       /* Find the section they want */
+       for (i = 1; i < ehdr->e_shnum; i++) {
+               if (strcmp(secnames + sechdrs[i].sh_name, name) == 0) {
+                       if (size)
+                               *size = sechdrs[i].sh_size;
+                       return (void *)ehdr + sechdrs[i].sh_offset;
+               }
+       }
+
+       if (size)
+               *size = 0;
+       return NULL;
+}
+
+static Elf32_Sym * __init find_symbol(struct elfinfo *lib, const char *symname)
+{
+       unsigned int i;
+
+       for (i = 0; i < (lib->dynsymsize / sizeof(Elf32_Sym)); i++) {
+               char name[MAX_SYMNAME], *c;
+
+               if (lib->dynsym[i].st_name == 0)
+                       continue;
+               strlcpy(name, lib->dynstr + lib->dynsym[i].st_name,
+                       MAX_SYMNAME);
+               c = strchr(name, '@');
+               if (c)
+                       *c = 0;
+               if (strcmp(symname, name) == 0)
+                       return &lib->dynsym[i];
+       }
+       return NULL;
+}
+
+static void __init vdso_nullpatch_one(struct elfinfo *lib, const char *symname)
+{
+       Elf32_Sym *sym;
+
+       sym = find_symbol(lib, symname);
+       if (!sym)
+               return;
+
+       sym->st_name = 0;
+}
+
+static void __init patch_vdso(void *ehdr)
+{
+       struct elfinfo einfo;
+
+       einfo = (struct elfinfo) {
+               .hdr = ehdr,
+       };
+
+       einfo.dynsym = find_section(einfo.hdr, ".dynsym", &einfo.dynsymsize);
+       einfo.dynstr = find_section(einfo.hdr, ".dynstr", NULL);
+
+       /* If the virtual counter is absent or non-functional we don't
+        * want programs to incur the slight additional overhead of
+        * dispatching through the VDSO only to fall back to syscalls.
+        */
+       if (!cntvct_ok) {
+               vdso_nullpatch_one(&einfo, "__vdso_gettimeofday");
+               vdso_nullpatch_one(&einfo, "__vdso_clock_gettime");
+       }
+}
+
+static int __init vdso_init(void)
+{
+       unsigned int text_pages;
+       int i;
+
+       if (memcmp(&vdso_start, "\177ELF", 4)) {
+               pr_err("VDSO is not a valid ELF object!\n");
+               return -ENOEXEC;
+       }
+
+       text_pages = (&vdso_end - &vdso_start) >> PAGE_SHIFT;
+       pr_debug("vdso: %i text pages at base %p\n", text_pages, &vdso_start);
+
+       /* Allocate the VDSO text pagelist */
+       vdso_text_pagelist = kcalloc(text_pages, sizeof(struct page *),
+                                    GFP_KERNEL);
+       if (vdso_text_pagelist == NULL)
+               return -ENOMEM;
+
+       /* Grab the VDSO data page. */
+       vdso_data_page = virt_to_page(vdso_data);
+
+       /* Grab the VDSO text pages. */
+       for (i = 0; i < text_pages; i++) {
+               struct page *page;
+
+               page = virt_to_page(&vdso_start + i * PAGE_SIZE);
+               vdso_text_pagelist[i] = page;
+       }
+
+       vdso_text_mapping.pages = vdso_text_pagelist;
+
+       vdso_total_pages = 1; /* for the data/vvar page */
+       vdso_total_pages += text_pages;
+
+       cntvct_ok = cntvct_functional();
+
+       patch_vdso(&vdso_start);
+
+       return 0;
+}
+arch_initcall(vdso_init);
+
+static int install_vvar(struct mm_struct *mm, unsigned long addr)
+{
+       struct vm_area_struct *vma;
+
+       vma = _install_special_mapping(mm, addr, PAGE_SIZE,
+                                      VM_READ | VM_MAYREAD,
+                                      &vdso_data_mapping);
+
+       return IS_ERR(vma) ? PTR_ERR(vma) : 0;
+}
+
+/* assumes mmap_sem is write-locked */
+void arm_install_vdso(struct mm_struct *mm, unsigned long addr)
+{
+       struct vm_area_struct *vma;
+       unsigned long len;
+
+       mm->context.vdso = 0;
+
+       if (vdso_text_pagelist == NULL)
+               return;
+
+       if (install_vvar(mm, addr))
+               return;
+
+       /* Account for vvar page. */
+       addr += PAGE_SIZE;
+       len = (vdso_total_pages - 1) << PAGE_SHIFT;
+
+       vma = _install_special_mapping(mm, addr, len,
+               VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC,
+               &vdso_text_mapping);
+
+       if (!IS_ERR(vma))
+               mm->context.vdso = addr;
+}
+
+static void vdso_write_begin(struct vdso_data *vdata)
+{
+       ++vdso_data->seq_count;
+       smp_wmb(); /* Pairs with smp_rmb in vdso_read_retry */
+}
+
+static void vdso_write_end(struct vdso_data *vdata)
+{
+       smp_wmb(); /* Pairs with smp_rmb in vdso_read_begin */
+       ++vdso_data->seq_count;
+}
+
+static bool tk_is_cntvct(const struct timekeeper *tk)
+{
+       if (!IS_ENABLED(CONFIG_ARM_ARCH_TIMER))
+               return false;
+
+       if (strcmp(tk->tkr.clock->name, "arch_sys_counter") != 0)
+               return false;
+
+       return true;
+}
+
+/**
+ * update_vsyscall - update the vdso data page
+ *
+ * Increment the sequence counter, making it odd, indicating to
+ * userspace that an update is in progress.  Update the fields used
+ * for coarse clocks and, if the architected system timer is in use,
+ * the fields used for high precision clocks.  Increment the sequence
+ * counter again, making it even, indicating to userspace that the
+ * update is finished.
+ *
+ * Userspace is expected to sample seq_count before reading any other
+ * fields from the data page.  If seq_count is odd, userspace is
+ * expected to wait until it becomes even.  After copying data from
+ * the page, userspace must sample seq_count again; if it has changed
+ * from its previous value, userspace must retry the whole sequence.
+ *
+ * Calls to update_vsyscall are serialized by the timekeeping core.
+ */
+void update_vsyscall(struct timekeeper *tk)
+{
+       struct timespec xtime_coarse;
+       struct timespec64 *wtm = &tk->wall_to_monotonic;
+
+       if (!cntvct_ok) {
+               /* The entry points have been zeroed, so there is no
+                * point in updating the data page.
+                */
+               return;
+       }
+
+       vdso_write_begin(vdso_data);
+
+       xtime_coarse = __current_kernel_time();
+       vdso_data->tk_is_cntvct                 = tk_is_cntvct(tk);
+       vdso_data->xtime_coarse_sec             = xtime_coarse.tv_sec;
+       vdso_data->xtime_coarse_nsec            = xtime_coarse.tv_nsec;
+       vdso_data->wtm_clock_sec                = wtm->tv_sec;
+       vdso_data->wtm_clock_nsec               = wtm->tv_nsec;
+
+       if (vdso_data->tk_is_cntvct) {
+               vdso_data->cs_cycle_last        = tk->tkr.cycle_last;
+               vdso_data->xtime_clock_sec      = tk->xtime_sec;
+               vdso_data->xtime_clock_snsec    = tk->tkr.xtime_nsec;
+               vdso_data->cs_mult              = tk->tkr.mult;
+               vdso_data->cs_shift             = tk->tkr.shift;
+               vdso_data->cs_mask              = tk->tkr.mask;
+       }
+
+       vdso_write_end(vdso_data);
+
+       flush_dcache_page(virt_to_page(vdso_data));
+}
+
+void update_vsyscall_tz(void)
+{
+       vdso_data->tz_minuteswest       = sys_tz.tz_minuteswest;
+       vdso_data->tz_dsttime           = sys_tz.tz_dsttime;
+       flush_dcache_page(virt_to_page(vdso_data));
+}
index b31aa73e80765539ce14018a1ed2fdc0a1a81ddc..7a301be9ac6784e999f2aa44a91cae1edb3f62a0 100644 (file)
@@ -74,7 +74,7 @@ SECTIONS
                ARM_EXIT_DISCARD(EXIT_DATA)
                EXIT_CALL
 #ifndef CONFIG_MMU
-               *(.fixup)
+               *(.text.fixup)
                *(__ex_table)
 #endif
 #ifndef CONFIG_SMP_ON_UP
@@ -100,6 +100,7 @@ SECTIONS
 
        .text : {                       /* Real text segment            */
                _stext = .;             /* Text and read-only data      */
+                       IDMAP_TEXT
                        __exception_text_start = .;
                        *(.exception.text)
                        __exception_text_end = .;
@@ -108,10 +109,6 @@ SECTIONS
                        SCHED_TEXT
                        LOCK_TEXT
                        KPROBES_TEXT
-                       IDMAP_TEXT
-#ifdef CONFIG_MMU
-                       *(.fixup)
-#endif
                        *(.gnu.warning)
                        *(.glue_7)
                        *(.glue_7t)
index 14a0d988c82cb41ab88acd4d924bf75aa87efce3..1710fd7db2d57d35ed342417336980f987db5985 100644 (file)
@@ -47,7 +47,7 @@ USER(         strnebt r2, [r0])
 ENDPROC(__clear_user)
 ENDPROC(__clear_user_std)
 
-               .pushsection .fixup,"ax"
+               .pushsection .text.fixup,"ax"
                .align  0
 9001:          ldmfd   sp!, {r0, pc}
                .popsection
index a9d3db16ecb5738234dc14defe8a4d2f21f60fef..9648b0675a3efc81dd412fa5b3be820c1a3d6242 100644 (file)
@@ -100,7 +100,7 @@ WEAK(__copy_to_user)
 ENDPROC(__copy_to_user)
 ENDPROC(__copy_to_user_std)
 
-       .pushsection .fixup,"ax"
+       .pushsection .text.fixup,"ax"
        .align 0
        copy_abort_preamble
        ldmfd   sp!, {r1, r2, r3}
index 7d08b43d2c0e496fc704378301b82d3b34d93f3a..1d0957e61f898ab6ab43759496e85c8b247218d1 100644 (file)
@@ -68,7 +68,7 @@
  * so properly, we would have to add in whatever registers were loaded before
  * the fault, which, with the current asm above is not predictable.
  */
-               .pushsection .fixup,"ax"
+               .pushsection .text.fixup,"ax"
                .align  4
 9001:          mov     r4, #-EFAULT
                ldr     r5, [sp, #8*4]          @ *err_ptr
index 31d25834b9c4b04d5e8a57adf39aa9083c38d027..cf950790fbdceb470643b5e8c152394deb2d46e5 100644 (file)
 #define CPU_MASK       0xff0ffff0
 #define CPU_CORTEX_A9  0x410fc090
 
-       /*
-        * The following code is located into the .data section. This is to
-        * allow l2x0_regs_phys to be accessed with a relative load while we
-        * can't rely on any MMU translation. We could have put l2x0_regs_phys
-        * in the .text section as well, but some setups might insist on it to
-        * be truly read-only. (Reference from: arch/arm/kernel/sleep.S)
-        */
-       .data
+       .text
        .align
 
        /*
@@ -69,10 +62,12 @@ ENTRY(exynos_cpu_resume_ns)
        cmp     r0, r1
        bne     skip_cp15
 
-       adr     r0, cp15_save_power
+       adr     r0, _cp15_save_power
        ldr     r1, [r0]
-       adr     r0, cp15_save_diag
+       ldr     r1, [r0, r1]
+       adr     r0, _cp15_save_diag
        ldr     r2, [r0]
+       ldr     r2, [r0, r2]
        mov     r0, #SMC_CMD_C15RESUME
        dsb
        smc     #0
@@ -118,14 +113,20 @@ skip_l2x0:
 skip_cp15:
        b       cpu_resume
 ENDPROC(exynos_cpu_resume_ns)
+
+       .align
+_cp15_save_power:
+       .long   cp15_save_power - .
+_cp15_save_diag:
+       .long   cp15_save_diag - .
+#ifdef CONFIG_CACHE_L2X0
+1:     .long   l2x0_saved_regs - .
+#endif /* CONFIG_CACHE_L2X0 */
+
+       .data
        .globl cp15_save_diag
 cp15_save_diag:
        .long   0       @ cp15 diagnostic
        .globl cp15_save_power
 cp15_save_power:
        .long   0       @ cp15 power control
-
-#ifdef CONFIG_CACHE_L2X0
-       .align
-1:     .long   l2x0_saved_regs - .
-#endif /* CONFIG_CACHE_L2X0 */
index 7c43ddd33ba84be2ee7fd8fa689f6f65ebab78d3..dfbfc0f7f8b82c140c6f82a673b6f638c377f4d1 100644 (file)
@@ -14,7 +14,7 @@
 
 #include <linux/linkage.h>
 
-       .data
+       .text
        .align
 
        /*
index 133ecff6664ec131e4b34c30200ace2fd683f404..b7644310236b1748c97da4196e5c473791a32a16 100644 (file)
@@ -825,6 +825,20 @@ config KUSER_HELPERS
          Say N here only if you are absolutely certain that you do not
          need these helpers; otherwise, the safe option is to say Y.
 
+config VDSO
+       bool "Enable VDSO for acceleration of some system calls"
+       depends on AEABI && MMU
+       default y if ARM_ARCH_TIMER
+       select GENERIC_TIME_VSYSCALL
+       help
+         Place in the process address space an ELF shared object
+         providing fast implementations of gettimeofday and
+         clock_gettime.  Systems that implement the ARM architected
+         timer will receive maximum benefit.
+
+         You must have glibc 2.22 or later for programs to seamlessly
+         take advantage of this.
+
 config DMA_CACHE_RWFO
        bool "Enable read/write for ownership DMA cache maintenance"
        depends on CPU_V6K && SMP
index 2c0c541c60caaafe76943ec3bb65a79da990f5c2..9769f1eefe3bc51b29188576a5e2aacc2f1dcedc 100644 (file)
@@ -201,7 +201,7 @@ union offset_union {
  THUMB(        "1:     "ins"   %1, [%2]\n"     )               \
  THUMB(        "       add     %2, %2, #1\n"   )               \
        "2:\n"                                          \
-       "       .pushsection .fixup,\"ax\"\n"           \
+       "       .pushsection .text.fixup,\"ax\"\n"      \
        "       .align  2\n"                            \
        "3:     mov     %0, #1\n"                       \
        "       b       2b\n"                           \
@@ -261,7 +261,7 @@ union offset_union {
                "       mov     %1, %1, "NEXT_BYTE"\n"          \
                "2:     "ins"   %1, [%2]\n"                     \
                "3:\n"                                          \
-               "       .pushsection .fixup,\"ax\"\n"           \
+               "       .pushsection .text.fixup,\"ax\"\n"      \
                "       .align  2\n"                            \
                "4:     mov     %0, #1\n"                       \
                "       b       3b\n"                           \
@@ -301,7 +301,7 @@ union offset_union {
                "       mov     %1, %1, "NEXT_BYTE"\n"          \
                "4:     "ins"   %1, [%2]\n"                     \
                "5:\n"                                          \
-               "       .pushsection .fixup,\"ax\"\n"           \
+               "       .pushsection .text.fixup,\"ax\"\n"      \
                "       .align  2\n"                            \
                "6:     mov     %0, #1\n"                       \
                "       b       5b\n"                           \
index 8f15f70622a6aa30a9ff7f20fb6cea3a963fc53b..e309c8f35af5af61e1d267bc212d7e4f08fbd786 100644 (file)
@@ -1647,6 +1647,7 @@ int __init l2x0_of_init(u32 aux_val, u32 aux_mask)
        struct device_node *np;
        struct resource res;
        u32 cache_id, old_aux;
+       u32 cache_level = 2;
 
        np = of_find_matching_node(NULL, l2x0_ids);
        if (!np)
@@ -1679,6 +1680,12 @@ int __init l2x0_of_init(u32 aux_val, u32 aux_mask)
        if (!of_property_read_bool(np, "cache-unified"))
                pr_err("L2C: device tree omits to specify unified cache\n");
 
+       if (of_property_read_u32(np, "cache-level", &cache_level))
+               pr_err("L2C: device tree omits to specify cache-level\n");
+
+       if (cache_level != 2)
+               pr_err("L2C: device tree specifies invalid cache level\n");
+
        /* Read back current (default) hardware configuration */
        if (data->save)
                data->save(l2x0_base);
index b966656d2c2d127aa4f9e7e9c840f58a143b5e1b..a134d8a13d001ee8ad4b1084c9a71c1dc9f8d832 100644 (file)
@@ -36,10 +36,10 @@ ENTRY(v7_invalidate_l1)
        mcr     p15, 2, r0, c0, c0, 0
        mrc     p15, 1, r0, c0, c0, 0
 
-       ldr     r1, =0x7fff
+       movw    r1, #0x7fff
        and     r2, r1, r0, lsr #13
 
-       ldr     r1, =0x3ff
+       movw    r1, #0x3ff
 
        and     r3, r1, r0, lsr #3      @ NumWays - 1
        add     r2, r2, #1              @ NumSets
@@ -90,21 +90,20 @@ ENDPROC(v7_flush_icache_all)
 ENTRY(v7_flush_dcache_louis)
        dmb                                     @ ensure ordering with previous memory accesses
        mrc     p15, 1, r0, c0, c0, 1           @ read clidr, r0 = clidr
-       ALT_SMP(ands    r3, r0, #(7 << 21))     @ extract LoUIS from clidr
-       ALT_UP(ands     r3, r0, #(7 << 27))     @ extract LoUU from clidr
+ALT_SMP(mov    r3, r0, lsr #20)                @ move LoUIS into position
+ALT_UP(        mov     r3, r0, lsr #26)                @ move LoUU into position
+       ands    r3, r3, #7 << 1                 @ extract LoU*2 field from clidr
+       bne     start_flush_levels              @ LoU != 0, start flushing
 #ifdef CONFIG_ARM_ERRATA_643719
-       ALT_SMP(mrceq   p15, 0, r2, c0, c0, 0)  @ read main ID register
-       ALT_UP(reteq    lr)                     @ LoUU is zero, so nothing to do
-       ldreq   r1, =0x410fc090                 @ ID of ARM Cortex A9 r0p?
-       biceq   r2, r2, #0x0000000f             @ clear minor revision number
-       teqeq   r2, r1                          @ test for errata affected core and if so...
-       orreqs  r3, #(1 << 21)                  @   fix LoUIS value (and set flags state to 'ne')
+ALT_SMP(mrc    p15, 0, r2, c0, c0, 0)          @ read main ID register
+ALT_UP(        ret     lr)                             @ LoUU is zero, so nothing to do
+       movw    r1, #:lower16:(0x410fc090 >> 4) @ ID of ARM Cortex A9 r0p?
+       movt    r1, #:upper16:(0x410fc090 >> 4)
+       teq     r1, r2, lsr #4                  @ test for errata affected core and if so...
+       moveq   r3, #1 << 1                     @   fix LoUIS value
+       beq     start_flush_levels              @   start flushing cache levels
 #endif
-       ALT_SMP(mov     r3, r3, lsr #20)        @ r3 = LoUIS * 2
-       ALT_UP(mov      r3, r3, lsr #26)        @ r3 = LoUU * 2
-       reteq   lr                              @ return if level == 0
-       mov     r10, #0                         @ r10 (starting level) = 0
-       b       flush_levels                    @ start flushing cache levels
+       ret     lr
 ENDPROC(v7_flush_dcache_louis)
 
 /*
@@ -119,9 +118,10 @@ ENDPROC(v7_flush_dcache_louis)
 ENTRY(v7_flush_dcache_all)
        dmb                                     @ ensure ordering with previous memory accesses
        mrc     p15, 1, r0, c0, c0, 1           @ read clidr
-       ands    r3, r0, #0x7000000              @ extract loc from clidr
-       mov     r3, r3, lsr #23                 @ left align loc bit field
+       mov     r3, r0, lsr #23                 @ move LoC into position
+       ands    r3, r3, #7 << 1                 @ extract LoC*2 from clidr
        beq     finished                        @ if loc is 0, then no need to clean
+start_flush_levels:
        mov     r10, #0                         @ start clean at cache level 0
 flush_levels:
        add     r2, r10, r10, lsr #1            @ work out 3x current cache level
@@ -140,10 +140,10 @@ flush_levels:
 #endif
        and     r2, r1, #7                      @ extract the length of the cache lines
        add     r2, r2, #4                      @ add 4 (line length offset)
-       ldr     r4, =0x3ff
+       movw    r4, #0x3ff
        ands    r4, r4, r1, lsr #3              @ find maximum number on the way size
        clz     r5, r4                          @ find bit position of way size increment
-       ldr     r7, =0x7fff
+       movw    r7, #0x7fff
        ands    r7, r7, r1, lsr #13             @ extract max number of the index size
 loop1:
        mov     r9, r7                          @ create working copy of max index
index f9941cd689e971422b13706922a99199772f4e95..3866f81c70bc3e246d7966a5c0815b32430cdefc 100644 (file)
@@ -289,11 +289,11 @@ static void __dma_free_buffer(struct page *page, size_t size)
 
 static void *__alloc_from_contiguous(struct device *dev, size_t size,
                                     pgprot_t prot, struct page **ret_page,
-                                    const void *caller);
+                                    const void *caller, bool want_vaddr);
 
 static void *__alloc_remap_buffer(struct device *dev, size_t size, gfp_t gfp,
                                 pgprot_t prot, struct page **ret_page,
-                                const void *caller);
+                                const void *caller, bool want_vaddr);
 
 static void *
 __dma_alloc_remap(struct page *page, size_t size, gfp_t gfp, pgprot_t prot,
@@ -357,10 +357,10 @@ static int __init atomic_pool_init(void)
 
        if (dev_get_cma_area(NULL))
                ptr = __alloc_from_contiguous(NULL, atomic_pool_size, prot,
-                                             &page, atomic_pool_init);
+                                             &page, atomic_pool_init, true);
        else
                ptr = __alloc_remap_buffer(NULL, atomic_pool_size, gfp, prot,
-                                          &page, atomic_pool_init);
+                                          &page, atomic_pool_init, true);
        if (ptr) {
                int ret;
 
@@ -467,13 +467,15 @@ static void __dma_remap(struct page *page, size_t size, pgprot_t prot)
 
 static void *__alloc_remap_buffer(struct device *dev, size_t size, gfp_t gfp,
                                 pgprot_t prot, struct page **ret_page,
-                                const void *caller)
+                                const void *caller, bool want_vaddr)
 {
        struct page *page;
-       void *ptr;
+       void *ptr = NULL;
        page = __dma_alloc_buffer(dev, size, gfp);
        if (!page)
                return NULL;
+       if (!want_vaddr)
+               goto out;
 
        ptr = __dma_alloc_remap(page, size, gfp, prot, caller);
        if (!ptr) {
@@ -481,6 +483,7 @@ static void *__alloc_remap_buffer(struct device *dev, size_t size, gfp_t gfp,
                return NULL;
        }
 
+ out:
        *ret_page = page;
        return ptr;
 }
@@ -523,12 +526,12 @@ static int __free_from_pool(void *start, size_t size)
 
 static void *__alloc_from_contiguous(struct device *dev, size_t size,
                                     pgprot_t prot, struct page **ret_page,
-                                    const void *caller)
+                                    const void *caller, bool want_vaddr)
 {
        unsigned long order = get_order(size);
        size_t count = size >> PAGE_SHIFT;
        struct page *page;
-       void *ptr;
+       void *ptr = NULL;
 
        page = dma_alloc_from_contiguous(dev, count, order);
        if (!page)
@@ -536,6 +539,9 @@ static void *__alloc_from_contiguous(struct device *dev, size_t size,
 
        __dma_clear_buffer(page, size);
 
+       if (!want_vaddr)
+               goto out;
+
        if (PageHighMem(page)) {
                ptr = __dma_alloc_remap(page, size, GFP_KERNEL, prot, caller);
                if (!ptr) {
@@ -546,17 +552,21 @@ static void *__alloc_from_contiguous(struct device *dev, size_t size,
                __dma_remap(page, size, prot);
                ptr = page_address(page);
        }
+
+ out:
        *ret_page = page;
        return ptr;
 }
 
 static void __free_from_contiguous(struct device *dev, struct page *page,
-                                  void *cpu_addr, size_t size)
+                                  void *cpu_addr, size_t size, bool want_vaddr)
 {
-       if (PageHighMem(page))
-               __dma_free_remap(cpu_addr, size);
-       else
-               __dma_remap(page, size, PAGE_KERNEL);
+       if (want_vaddr) {
+               if (PageHighMem(page))
+                       __dma_free_remap(cpu_addr, size);
+               else
+                       __dma_remap(page, size, PAGE_KERNEL);
+       }
        dma_release_from_contiguous(dev, page, size >> PAGE_SHIFT);
 }
 
@@ -574,12 +584,12 @@ static inline pgprot_t __get_dma_pgprot(struct dma_attrs *attrs, pgprot_t prot)
 
 #define nommu() 1
 
-#define __get_dma_pgprot(attrs, prot)  __pgprot(0)
-#define __alloc_remap_buffer(dev, size, gfp, prot, ret, c)     NULL
+#define __get_dma_pgprot(attrs, prot)                          __pgprot(0)
+#define __alloc_remap_buffer(dev, size, gfp, prot, ret, c, wv) NULL
 #define __alloc_from_pool(size, ret_page)                      NULL
-#define __alloc_from_contiguous(dev, size, prot, ret, c)       NULL
+#define __alloc_from_contiguous(dev, size, prot, ret, c, wv)   NULL
 #define __free_from_pool(cpu_addr, size)                       0
-#define __free_from_contiguous(dev, page, cpu_addr, size)      do { } while (0)
+#define __free_from_contiguous(dev, page, cpu_addr, size, wv)  do { } while (0)
 #define __dma_free_remap(cpu_addr, size)                       do { } while (0)
 
 #endif /* CONFIG_MMU */
@@ -599,11 +609,13 @@ static void *__alloc_simple_buffer(struct device *dev, size_t size, gfp_t gfp,
 
 
 static void *__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
-                        gfp_t gfp, pgprot_t prot, bool is_coherent, const void *caller)
+                        gfp_t gfp, pgprot_t prot, bool is_coherent,
+                        struct dma_attrs *attrs, const void *caller)
 {
        u64 mask = get_coherent_dma_mask(dev);
        struct page *page = NULL;
        void *addr;
+       bool want_vaddr;
 
 #ifdef CONFIG_DMA_API_DEBUG
        u64 limit = (mask + 1) & ~mask;
@@ -631,20 +643,21 @@ static void *__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
 
        *handle = DMA_ERROR_CODE;
        size = PAGE_ALIGN(size);
+       want_vaddr = !dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, attrs);
 
        if (is_coherent || nommu())
                addr = __alloc_simple_buffer(dev, size, gfp, &page);
        else if (!(gfp & __GFP_WAIT))
                addr = __alloc_from_pool(size, &page);
        else if (!dev_get_cma_area(dev))
-               addr = __alloc_remap_buffer(dev, size, gfp, prot, &page, caller);
+               addr = __alloc_remap_buffer(dev, size, gfp, prot, &page, caller, want_vaddr);
        else
-               addr = __alloc_from_contiguous(dev, size, prot, &page, caller);
+               addr = __alloc_from_contiguous(dev, size, prot, &page, caller, want_vaddr);
 
-       if (addr)
+       if (page)
                *handle = pfn_to_dma(dev, page_to_pfn(page));
 
-       return addr;
+       return want_vaddr ? addr : page;
 }
 
 /*
@@ -661,7 +674,7 @@ void *arm_dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
                return memory;
 
        return __dma_alloc(dev, size, handle, gfp, prot, false,
-                          __builtin_return_address(0));
+                          attrs, __builtin_return_address(0));
 }
 
 static void *arm_coherent_dma_alloc(struct device *dev, size_t size,
@@ -674,7 +687,7 @@ static void *arm_coherent_dma_alloc(struct device *dev, size_t size,
                return memory;
 
        return __dma_alloc(dev, size, handle, gfp, prot, true,
-                          __builtin_return_address(0));
+                          attrs, __builtin_return_address(0));
 }
 
 /*
@@ -715,6 +728,7 @@ static void __arm_dma_free(struct device *dev, size_t size, void *cpu_addr,
                           bool is_coherent)
 {
        struct page *page = pfn_to_page(dma_to_pfn(dev, handle));
+       bool want_vaddr = !dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, attrs);
 
        if (dma_release_from_coherent(dev, get_order(size), cpu_addr))
                return;
@@ -726,14 +740,15 @@ static void __arm_dma_free(struct device *dev, size_t size, void *cpu_addr,
        } else if (__free_from_pool(cpu_addr, size)) {
                return;
        } else if (!dev_get_cma_area(dev)) {
-               __dma_free_remap(cpu_addr, size);
+               if (want_vaddr)
+                       __dma_free_remap(cpu_addr, size);
                __dma_free_buffer(page, size);
        } else {
                /*
                 * Non-atomic allocations cannot be freed with IRQs disabled
                 */
                WARN_ON(irqs_disabled());
-               __free_from_contiguous(dev, page, cpu_addr, size);
+               __free_from_contiguous(dev, page, cpu_addr, size, want_vaddr);
        }
 }
 
@@ -1221,7 +1236,7 @@ __iommu_alloc_remap(struct page **pages, size_t size, gfp_t gfp, pgprot_t prot,
 static dma_addr_t
 __iommu_create_mapping(struct device *dev, struct page **pages, size_t size)
 {
-       struct dma_iommu_mapping *mapping = dev->archdata.mapping;
+       struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev);
        unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT;
        dma_addr_t dma_addr, iova;
        int i, ret = DMA_ERROR_CODE;
@@ -1257,7 +1272,7 @@ fail:
 
 static int __iommu_remove_mapping(struct device *dev, dma_addr_t iova, size_t size)
 {
-       struct dma_iommu_mapping *mapping = dev->archdata.mapping;
+       struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev);
 
        /*
         * add optional in-page offset from iova to size and align
@@ -1472,7 +1487,7 @@ static int __map_sg_chunk(struct device *dev, struct scatterlist *sg,
                          enum dma_data_direction dir, struct dma_attrs *attrs,
                          bool is_coherent)
 {
-       struct dma_iommu_mapping *mapping = dev->archdata.mapping;
+       struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev);
        dma_addr_t iova, iova_base;
        int ret = 0;
        unsigned int count;
@@ -1693,7 +1708,7 @@ static dma_addr_t arm_coherent_iommu_map_page(struct device *dev, struct page *p
             unsigned long offset, size_t size, enum dma_data_direction dir,
             struct dma_attrs *attrs)
 {
-       struct dma_iommu_mapping *mapping = dev->archdata.mapping;
+       struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev);
        dma_addr_t dma_addr;
        int ret, prot, len = PAGE_ALIGN(size + offset);
 
@@ -1746,7 +1761,7 @@ static void arm_coherent_iommu_unmap_page(struct device *dev, dma_addr_t handle,
                size_t size, enum dma_data_direction dir,
                struct dma_attrs *attrs)
 {
-       struct dma_iommu_mapping *mapping = dev->archdata.mapping;
+       struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev);
        dma_addr_t iova = handle & PAGE_MASK;
        int offset = handle & ~PAGE_MASK;
        int len = PAGE_ALIGN(size + offset);
@@ -1771,7 +1786,7 @@ static void arm_iommu_unmap_page(struct device *dev, dma_addr_t handle,
                size_t size, enum dma_data_direction dir,
                struct dma_attrs *attrs)
 {
-       struct dma_iommu_mapping *mapping = dev->archdata.mapping;
+       struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev);
        dma_addr_t iova = handle & PAGE_MASK;
        struct page *page = phys_to_page(iommu_iova_to_phys(mapping->domain, iova));
        int offset = handle & ~PAGE_MASK;
@@ -1790,7 +1805,7 @@ static void arm_iommu_unmap_page(struct device *dev, dma_addr_t handle,
 static void arm_iommu_sync_single_for_cpu(struct device *dev,
                dma_addr_t handle, size_t size, enum dma_data_direction dir)
 {
-       struct dma_iommu_mapping *mapping = dev->archdata.mapping;
+       struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev);
        dma_addr_t iova = handle & PAGE_MASK;
        struct page *page = phys_to_page(iommu_iova_to_phys(mapping->domain, iova));
        unsigned int offset = handle & ~PAGE_MASK;
@@ -1804,7 +1819,7 @@ static void arm_iommu_sync_single_for_cpu(struct device *dev,
 static void arm_iommu_sync_single_for_device(struct device *dev,
                dma_addr_t handle, size_t size, enum dma_data_direction dir)
 {
-       struct dma_iommu_mapping *mapping = dev->archdata.mapping;
+       struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev);
        dma_addr_t iova = handle & PAGE_MASK;
        struct page *page = phys_to_page(iommu_iova_to_phys(mapping->domain, iova));
        unsigned int offset = handle & ~PAGE_MASK;
@@ -1965,7 +1980,7 @@ static int __arm_iommu_attach_device(struct device *dev,
                return err;
 
        kref_get(&mapping->kref);
-       dev->archdata.mapping = mapping;
+       to_dma_iommu_mapping(dev) = mapping;
 
        pr_debug("Attached IOMMU controller to %s device.\n", dev_name(dev));
        return 0;
@@ -2010,7 +2025,7 @@ static void __arm_iommu_detach_device(struct device *dev)
 
        iommu_detach_device(mapping->domain, dev);
        kref_put(&mapping->kref, release_iommu_mapping);
-       dev->archdata.mapping = NULL;
+       to_dma_iommu_mapping(dev) = NULL;
 
        pr_debug("Detached IOMMU controller from %s device.\n", dev_name(dev));
 }
@@ -2061,7 +2076,7 @@ static bool arm_setup_iommu_dma_ops(struct device *dev, u64 dma_base, u64 size,
 
 static void arm_teardown_iommu_dma_ops(struct device *dev)
 {
-       struct dma_iommu_mapping *mapping = dev->archdata.mapping;
+       struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev);
 
        if (!mapping)
                return;
index 86ee5d47ce3ca7b86f6eff840238f06e93f323c4..aa0519eed6986c9af3b9b560663ea6e7b04f7c1a 100644 (file)
@@ -507,7 +507,7 @@ cpu_arm1020_name:
 
        .align
 
-       .section ".proc.info.init", #alloc, #execinstr
+       .section ".proc.info.init", #alloc
 
        .type   __arm1020_proc_info,#object
 __arm1020_proc_info:
@@ -519,7 +519,7 @@ __arm1020_proc_info:
        .long   PMD_TYPE_SECT | \
                PMD_SECT_AP_WRITE | \
                PMD_SECT_AP_READ
-       b       __arm1020_setup
+       initfn  __arm1020_setup, __arm1020_proc_info
        .long   cpu_arch_name
        .long   cpu_elf_name
        .long   HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB
index a6331d78601f679ae29048577c1f376ac21a99a6..bff4c7f70fd6a992d0587b99f1303a08776988b7 100644 (file)
@@ -465,7 +465,7 @@ arm1020e_crval:
 
        .align
 
-       .section ".proc.info.init", #alloc, #execinstr
+       .section ".proc.info.init", #alloc
 
        .type   __arm1020e_proc_info,#object
 __arm1020e_proc_info:
@@ -479,7 +479,7 @@ __arm1020e_proc_info:
                PMD_BIT4 | \
                PMD_SECT_AP_WRITE | \
                PMD_SECT_AP_READ
-       b       __arm1020e_setup
+       initfn  __arm1020e_setup, __arm1020e_proc_info
        .long   cpu_arch_name
        .long   cpu_elf_name
        .long   HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB | HWCAP_EDSP
index a126b7a5992809c93e911a7c875359b68c591085..dbb2413fe04dbd5babcd7dad8f41820448d518dc 100644 (file)
@@ -448,7 +448,7 @@ arm1022_crval:
 
        .align
 
-       .section ".proc.info.init", #alloc, #execinstr
+       .section ".proc.info.init", #alloc
 
        .type   __arm1022_proc_info,#object
 __arm1022_proc_info:
@@ -462,7 +462,7 @@ __arm1022_proc_info:
                PMD_BIT4 | \
                PMD_SECT_AP_WRITE | \
                PMD_SECT_AP_READ
-       b       __arm1022_setup
+       initfn  __arm1022_setup, __arm1022_proc_info
        .long   cpu_arch_name
        .long   cpu_elf_name
        .long   HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB | HWCAP_EDSP
index fc294067e9776330badad04d7276a9b4d56b2258..0b37b2cef9d32849b0162787ef06c7215814acb2 100644 (file)
@@ -442,7 +442,7 @@ arm1026_crval:
        string  cpu_arm1026_name, "ARM1026EJ-S"
        .align
 
-       .section ".proc.info.init", #alloc, #execinstr
+       .section ".proc.info.init", #alloc
 
        .type   __arm1026_proc_info,#object
 __arm1026_proc_info:
@@ -456,7 +456,7 @@ __arm1026_proc_info:
                PMD_BIT4 | \
                PMD_SECT_AP_WRITE | \
                PMD_SECT_AP_READ
-       b       __arm1026_setup
+       initfn  __arm1026_setup, __arm1026_proc_info
        .long   cpu_arch_name
        .long   cpu_elf_name
        .long   HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_JAVA
index 2baa66b3ac9b749ee8f8a32f8e16169ada2039c9..3651cd70e4181c6584259b3b19a50729d38dea19 100644 (file)
@@ -186,7 +186,7 @@ arm720_crval:
  * See <asm/procinfo.h> for a definition of this structure.
  */
        
-               .section ".proc.info.init", #alloc, #execinstr
+               .section ".proc.info.init", #alloc
 
 .macro arm720_proc_info name:req, cpu_val:req, cpu_mask:req, cpu_name:req, cpu_flush:req
                .type   __\name\()_proc_info,#object
@@ -203,7 +203,7 @@ __\name\()_proc_info:
                        PMD_BIT4 | \
                        PMD_SECT_AP_WRITE | \
                        PMD_SECT_AP_READ
-               b       \cpu_flush                              @ cpu_flush
+               initfn  \cpu_flush, __\name\()_proc_info        @ cpu_flush
                .long   cpu_arch_name                           @ arch_name
                .long   cpu_elf_name                            @ elf_name
                .long   HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB    @ elf_hwcap
index ac1ea6b3bce4c13d4e87e6b14e547849aeb00648..024fb7732407d6c25701e4698843e8b27fb66da1 100644 (file)
@@ -132,14 +132,14 @@ __arm740_setup:
 
        .align
 
-       .section ".proc.info.init", #alloc, #execinstr
+       .section ".proc.info.init", #alloc
        .type   __arm740_proc_info,#object
 __arm740_proc_info:
        .long   0x41807400
        .long   0xfffffff0
        .long   0
        .long   0
-       b       __arm740_setup
+       initfn  __arm740_setup, __arm740_proc_info
        .long   cpu_arch_name
        .long   cpu_elf_name
        .long   HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB | HWCAP_26BIT
index bf6ba4bc30ffb87acd4ddf2d7b83cd710f52f43b..25472d94426d2c8a5f6d56456632b4f2406b9eab 100644 (file)
@@ -76,7 +76,7 @@ __arm7tdmi_setup:
 
                .align
 
-               .section ".proc.info.init", #alloc, #execinstr
+               .section ".proc.info.init", #alloc
 
 .macro arm7tdmi_proc_info name:req, cpu_val:req, cpu_mask:req, cpu_name:req, \
        extra_hwcaps=0
@@ -86,7 +86,7 @@ __\name\()_proc_info:
                .long   \cpu_mask
                .long   0
                .long   0
-               b       __arm7tdmi_setup
+               initfn  __arm7tdmi_setup, __\name\()_proc_info
                .long   cpu_arch_name
                .long   cpu_elf_name
                .long   HWCAP_SWP | HWCAP_26BIT | ( \extra_hwcaps )
index 22bf8dde4f84b331a07e740800785791dfb852f9..7a14bd4414c9ca5fdce13b3eedc458ef1fa6f377 100644 (file)
@@ -448,7 +448,7 @@ arm920_crval:
 
        .align
 
-       .section ".proc.info.init", #alloc, #execinstr
+       .section ".proc.info.init", #alloc
 
        .type   __arm920_proc_info,#object
 __arm920_proc_info:
@@ -464,7 +464,7 @@ __arm920_proc_info:
                PMD_BIT4 | \
                PMD_SECT_AP_WRITE | \
                PMD_SECT_AP_READ
-       b       __arm920_setup
+       initfn  __arm920_setup, __arm920_proc_info
        .long   cpu_arch_name
        .long   cpu_elf_name
        .long   HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB
index 0c6d5ac5a6d41b10a8480597056752cc5325a727..edccfcdcd551fe9e9970172d0467d5ddd3324bba 100644 (file)
@@ -426,7 +426,7 @@ arm922_crval:
 
        .align
 
-       .section ".proc.info.init", #alloc, #execinstr
+       .section ".proc.info.init", #alloc
 
        .type   __arm922_proc_info,#object
 __arm922_proc_info:
@@ -442,7 +442,7 @@ __arm922_proc_info:
                PMD_BIT4 | \
                PMD_SECT_AP_WRITE | \
                PMD_SECT_AP_READ
-       b       __arm922_setup
+       initfn  __arm922_setup, __arm922_proc_info
        .long   cpu_arch_name
        .long   cpu_elf_name
        .long   HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB
index c32d073282eabbf7ada03d814ba236e989c23d18..ede8c54ab4aa751d9619b6fec3248cac4255ee40 100644 (file)
@@ -494,7 +494,7 @@ arm925_crval:
 
        .align
 
-       .section ".proc.info.init", #alloc, #execinstr
+       .section ".proc.info.init", #alloc
 
 .macro arm925_proc_info name:req, cpu_val:req, cpu_mask:req, cpu_name:req, cache
        .type   __\name\()_proc_info,#object
@@ -510,7 +510,7 @@ __\name\()_proc_info:
                PMD_BIT4 | \
                PMD_SECT_AP_WRITE | \
                PMD_SECT_AP_READ
-       b       __arm925_setup
+       initfn  __arm925_setup, __\name\()_proc_info
        .long   cpu_arch_name
        .long   cpu_elf_name
        .long   HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB
index 252b2503038de72131f84aa79a585111c67e1837..fb827c633693c430b718dcb457f6850d8126d3e6 100644 (file)
@@ -474,7 +474,7 @@ arm926_crval:
 
        .align
 
-       .section ".proc.info.init", #alloc, #execinstr
+       .section ".proc.info.init", #alloc
 
        .type   __arm926_proc_info,#object
 __arm926_proc_info:
@@ -490,7 +490,7 @@ __arm926_proc_info:
                PMD_BIT4 | \
                PMD_SECT_AP_WRITE | \
                PMD_SECT_AP_READ
-       b       __arm926_setup
+       initfn  __arm926_setup, __arm926_proc_info
        .long   cpu_arch_name
        .long   cpu_elf_name
        .long   HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_JAVA
index e5212d48937723e8fe711aadfba2ade276d2a442..0a0b7a9167b624d951c92364d459eaa7077c39e6 100644 (file)
@@ -354,14 +354,14 @@ __arm940_setup:
 
        .align
 
-       .section ".proc.info.init", #alloc, #execinstr
+       .section ".proc.info.init", #alloc
 
        .type   __arm940_proc_info,#object
 __arm940_proc_info:
        .long   0x41009400
        .long   0xff00fff0
        .long   0
-       b       __arm940_setup
+       initfn  __arm940_setup, __arm940_proc_info
        .long   cpu_arch_name
        .long   cpu_elf_name
        .long   HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB
index b3dd9b2d0b8ea01972bbfa9379fb3c7665ee2611..c85b40d2117ee1ae29420d2980d9c8a2ec000183 100644 (file)
@@ -409,14 +409,14 @@ __arm946_setup:
 
        .align
 
-       .section ".proc.info.init", #alloc, #execinstr
+       .section ".proc.info.init", #alloc
        .type   __arm946_proc_info,#object
 __arm946_proc_info:
        .long   0x41009460
        .long   0xff00fff0
        .long   0
        .long   0
-       b       __arm946_setup
+       initfn  __arm946_setup, __arm946_proc_info
        .long   cpu_arch_name
        .long   cpu_elf_name
        .long   HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB
index 8227322bbb8f86763d1e7039c08797165c223427..7fac8c6121349e03e96bd00694e379c499326e5b 100644 (file)
@@ -70,7 +70,7 @@ __arm9tdmi_setup:
 
                .align
 
-               .section ".proc.info.init", #alloc, #execinstr
+               .section ".proc.info.init", #alloc
 
 .macro arm9tdmi_proc_info name:req, cpu_val:req, cpu_mask:req, cpu_name:req
                .type   __\name\()_proc_info, #object
@@ -79,7 +79,7 @@ __\name\()_proc_info:
                .long   \cpu_mask
                .long   0
                .long   0
-               b       __arm9tdmi_setup
+               initfn  __arm9tdmi_setup, __\name\()_proc_info
                .long   cpu_arch_name
                .long   cpu_elf_name
                .long   HWCAP_SWP | HWCAP_THUMB | HWCAP_26BIT
index c494886892ba0d2a6f1bbff54f50b463fc2afbad..4001b73af4ee15cc722bf929573196cd4aeb4033 100644 (file)
@@ -190,7 +190,7 @@ fa526_cr1_set:
 
        .align
 
-       .section ".proc.info.init", #alloc, #execinstr
+       .section ".proc.info.init", #alloc
 
        .type   __fa526_proc_info,#object
 __fa526_proc_info:
@@ -206,7 +206,7 @@ __fa526_proc_info:
                PMD_BIT4 | \
                PMD_SECT_AP_WRITE | \
                PMD_SECT_AP_READ
-       b       __fa526_setup
+       initfn  __fa526_setup, __fa526_proc_info
        .long   cpu_arch_name
        .long   cpu_elf_name
        .long   HWCAP_SWP | HWCAP_HALF
index 03a1b75f2e1697d1c7fcec7c255767973eb96b3f..e494d6d6acbe8f38f316a586f474d7b7cfc3c0c0 100644 (file)
@@ -584,7 +584,7 @@ feroceon_crval:
 
        .align
 
-       .section ".proc.info.init", #alloc, #execinstr
+       .section ".proc.info.init", #alloc
 
 .macro feroceon_proc_info name:req, cpu_val:req, cpu_mask:req, cpu_name:req, cache:req
        .type   __\name\()_proc_info,#object
@@ -601,7 +601,8 @@ __\name\()_proc_info:
                PMD_BIT4 | \
                PMD_SECT_AP_WRITE | \
                PMD_SECT_AP_READ
-       b       __feroceon_setup
+       initfn  __feroceon_setup, __\name\()_proc_info
+       .long __feroceon_setup
        .long   cpu_arch_name
        .long   cpu_elf_name
        .long   HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
index 082b9f2f7e9001ce0b9ad1f990befec1dafc08d5..0f13b5f9281ecdcdf116d6ec1c589e3fd9474d83 100644 (file)
@@ -331,3 +331,7 @@ ENTRY(\name\()_tlb_fns)
        .globl  \x
        .equ    \x, \y
 .endm
+
+.macro initfn, func, base
+       .long   \func - \base
+.endm
index 53d393455f137685c3b5d65f0510e41810cb0374..d65edf717bf7333d792fee6a0922bde155c0d5bf 100644 (file)
@@ -427,7 +427,7 @@ mohawk_crval:
 
        .align
 
-       .section ".proc.info.init", #alloc, #execinstr
+       .section ".proc.info.init", #alloc
 
        .type   __88sv331x_proc_info,#object
 __88sv331x_proc_info:
@@ -443,7 +443,7 @@ __88sv331x_proc_info:
                PMD_BIT4 | \
                PMD_SECT_AP_WRITE | \
                PMD_SECT_AP_READ
-       b       __mohawk_setup
+       initfn  __mohawk_setup, __88sv331x_proc_info
        .long   cpu_arch_name
        .long   cpu_elf_name
        .long   HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
index 8008a0461cf530b70adb6d50d02e40094e5dccd4..ee2ce496239f57f14f3638e133a8fbd14e7d2bfa 100644 (file)
@@ -199,7 +199,7 @@ sa110_crval:
 
        .align
 
-       .section ".proc.info.init", #alloc, #execinstr
+       .section ".proc.info.init", #alloc
 
        .type   __sa110_proc_info,#object
 __sa110_proc_info:
@@ -213,7 +213,7 @@ __sa110_proc_info:
        .long   PMD_TYPE_SECT | \
                PMD_SECT_AP_WRITE | \
                PMD_SECT_AP_READ
-       b       __sa110_setup
+       initfn  __sa110_setup, __sa110_proc_info
        .long   cpu_arch_name
        .long   cpu_elf_name
        .long   HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT | HWCAP_FAST_MULT
index 89f97ac648a9d55d79c6668fb3ea43f492d307e9..222d5836f6664467fb5a5c6d18bc6240ba700593 100644 (file)
@@ -242,7 +242,7 @@ sa1100_crval:
 
        .align
 
-       .section ".proc.info.init", #alloc, #execinstr
+       .section ".proc.info.init", #alloc
 
 .macro sa1100_proc_info name:req, cpu_val:req, cpu_mask:req, cpu_name:req
        .type   __\name\()_proc_info,#object
@@ -257,7 +257,7 @@ __\name\()_proc_info:
        .long   PMD_TYPE_SECT | \
                PMD_SECT_AP_WRITE | \
                PMD_SECT_AP_READ
-       b       __sa1100_setup
+       initfn  __sa1100_setup, __\name\()_proc_info
        .long   cpu_arch_name
        .long   cpu_elf_name
        .long   HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT | HWCAP_FAST_MULT
index d0390f4b3f1893b152ee2dcea17f60e4031e279d..06d890a2342b1600e2eae6e350994ad59f5c3a08 100644 (file)
@@ -264,7 +264,7 @@ v6_crval:
        string  cpu_elf_name, "v6"
        .align
 
-       .section ".proc.info.init", #alloc, #execinstr
+       .section ".proc.info.init", #alloc
 
        /*
         * Match any ARMv6 processor core.
@@ -287,7 +287,7 @@ __v6_proc_info:
                PMD_SECT_XN | \
                PMD_SECT_AP_WRITE | \
                PMD_SECT_AP_READ
-       b       __v6_setup
+       initfn  __v6_setup, __v6_proc_info
        .long   cpu_arch_name
        .long   cpu_elf_name
        /* See also feat_v6_fixup() for HWCAP_TLS */
index 8b4ee5e81c146c1aaeafb79560c3af4d8a647f6a..6bdaa4cc17842dfc012717b96cd8791be3c7b254 100644 (file)
@@ -462,19 +462,19 @@ __v7_setup_stack:
        string  cpu_elf_name, "v7"
        .align
 
-       .section ".proc.info.init", #alloc, #execinstr
+       .section ".proc.info.init", #alloc
 
        /*
         * Standard v7 proc info content
         */
-.macro __v7_proc initfunc, mm_mmuflags = 0, io_mmuflags = 0, hwcaps = 0, proc_fns = v7_processor_functions
+.macro __v7_proc name, initfunc, mm_mmuflags = 0, io_mmuflags = 0, hwcaps = 0, proc_fns = v7_processor_functions
        ALT_SMP(.long   PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_AP_READ | \
                        PMD_SECT_AF | PMD_FLAGS_SMP | \mm_mmuflags)
        ALT_UP(.long    PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_AP_READ | \
                        PMD_SECT_AF | PMD_FLAGS_UP | \mm_mmuflags)
        .long   PMD_TYPE_SECT | PMD_SECT_AP_WRITE | \
                PMD_SECT_AP_READ | PMD_SECT_AF | \io_mmuflags
-       W(b)    \initfunc
+       initfn  \initfunc, \name
        .long   cpu_arch_name
        .long   cpu_elf_name
        .long   HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB | HWCAP_FAST_MULT | \
@@ -494,7 +494,7 @@ __v7_setup_stack:
 __v7_ca5mp_proc_info:
        .long   0x410fc050
        .long   0xff0ffff0
-       __v7_proc __v7_ca5mp_setup
+       __v7_proc __v7_ca5mp_proc_info, __v7_ca5mp_setup
        .size   __v7_ca5mp_proc_info, . - __v7_ca5mp_proc_info
 
        /*
@@ -504,7 +504,7 @@ __v7_ca5mp_proc_info:
 __v7_ca9mp_proc_info:
        .long   0x410fc090
        .long   0xff0ffff0
-       __v7_proc __v7_ca9mp_setup, proc_fns = ca9mp_processor_functions
+       __v7_proc __v7_ca9mp_proc_info, __v7_ca9mp_setup, proc_fns = ca9mp_processor_functions
        .size   __v7_ca9mp_proc_info, . - __v7_ca9mp_proc_info
 
 #endif /* CONFIG_ARM_LPAE */
@@ -517,7 +517,7 @@ __v7_ca9mp_proc_info:
 __v7_pj4b_proc_info:
        .long   0x560f5800
        .long   0xff0fff00
-       __v7_proc __v7_pj4b_setup, proc_fns = pj4b_processor_functions
+       __v7_proc __v7_pj4b_proc_info, __v7_pj4b_setup, proc_fns = pj4b_processor_functions
        .size   __v7_pj4b_proc_info, . - __v7_pj4b_proc_info
 #endif
 
@@ -528,7 +528,7 @@ __v7_pj4b_proc_info:
 __v7_cr7mp_proc_info:
        .long   0x410fc170
        .long   0xff0ffff0
-       __v7_proc __v7_cr7mp_setup
+       __v7_proc __v7_cr7mp_proc_info, __v7_cr7mp_setup
        .size   __v7_cr7mp_proc_info, . - __v7_cr7mp_proc_info
 
        /*
@@ -538,7 +538,7 @@ __v7_cr7mp_proc_info:
 __v7_ca7mp_proc_info:
        .long   0x410fc070
        .long   0xff0ffff0
-       __v7_proc __v7_ca7mp_setup
+       __v7_proc __v7_ca7mp_proc_info, __v7_ca7mp_setup
        .size   __v7_ca7mp_proc_info, . - __v7_ca7mp_proc_info
 
        /*
@@ -548,7 +548,7 @@ __v7_ca7mp_proc_info:
 __v7_ca12mp_proc_info:
        .long   0x410fc0d0
        .long   0xff0ffff0
-       __v7_proc __v7_ca12mp_setup
+       __v7_proc __v7_ca12mp_proc_info, __v7_ca12mp_setup
        .size   __v7_ca12mp_proc_info, . - __v7_ca12mp_proc_info
 
        /*
@@ -558,7 +558,7 @@ __v7_ca12mp_proc_info:
 __v7_ca15mp_proc_info:
        .long   0x410fc0f0
        .long   0xff0ffff0
-       __v7_proc __v7_ca15mp_setup
+       __v7_proc __v7_ca15mp_proc_info, __v7_ca15mp_setup
        .size   __v7_ca15mp_proc_info, . - __v7_ca15mp_proc_info
 
        /*
@@ -568,7 +568,7 @@ __v7_ca15mp_proc_info:
 __v7_b15mp_proc_info:
        .long   0x420f00f0
        .long   0xff0ffff0
-       __v7_proc __v7_b15mp_setup
+       __v7_proc __v7_b15mp_proc_info, __v7_b15mp_setup
        .size   __v7_b15mp_proc_info, . - __v7_b15mp_proc_info
 
        /*
@@ -578,7 +578,7 @@ __v7_b15mp_proc_info:
 __v7_ca17mp_proc_info:
        .long   0x410fc0e0
        .long   0xff0ffff0
-       __v7_proc __v7_ca17mp_setup
+       __v7_proc __v7_ca17mp_proc_info, __v7_ca17mp_setup
        .size   __v7_ca17mp_proc_info, . - __v7_ca17mp_proc_info
 
        /*
@@ -594,7 +594,7 @@ __krait_proc_info:
         * do support them. They also don't indicate support for fused multiply
         * instructions even though they actually do support them.
         */
-       __v7_proc __v7_setup, hwcaps = HWCAP_IDIV | HWCAP_VFPv4
+       __v7_proc __krait_proc_info, __v7_setup, hwcaps = HWCAP_IDIV | HWCAP_VFPv4
        .size   __krait_proc_info, . - __krait_proc_info
 
        /*
@@ -604,5 +604,5 @@ __krait_proc_info:
 __v7_proc_info:
        .long   0x000f0000              @ Required ID value
        .long   0x000f0000              @ Mask for ID
-       __v7_proc __v7_setup
+       __v7_proc __v7_proc_info, __v7_setup
        .size   __v7_proc_info, . - __v7_proc_info
index d1e68b553d3b4e6cfbae0d003be88e9786c7e3bc..e08e1f2bab76bad4926ecb4b02bbd91149e7d0a3 100644 (file)
@@ -135,7 +135,7 @@ __v7m_setup_stack_top:
        string cpu_elf_name "v7m"
        string cpu_v7m_name "ARMv7-M"
 
-       .section ".proc.info.init", #alloc, #execinstr
+       .section ".proc.info.init", #alloc
 
        /*
         * Match any ARMv7-M processor core.
@@ -146,7 +146,7 @@ __v7m_proc_info:
        .long   0x000f0000              @ Mask for ID
        .long   0                       @ proc_info_list.__cpu_mm_mmu_flags
        .long   0                       @ proc_info_list.__cpu_io_mmu_flags
-       b       __v7m_setup             @ proc_info_list.__cpu_flush
+       initfn  __v7m_setup, __v7m_proc_info    @ proc_info_list.__cpu_flush
        .long   cpu_arch_name
        .long   cpu_elf_name
        .long   HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT
index f8acdfece0363bb02516705af407fff89287b0b7..293dcc2c441f305f7b28d67dbf27a2276fdf2c25 100644 (file)
@@ -499,7 +499,7 @@ xsc3_crval:
 
        .align
 
-       .section ".proc.info.init", #alloc, #execinstr
+       .section ".proc.info.init", #alloc
 
 .macro xsc3_proc_info name:req, cpu_val:req, cpu_mask:req
        .type   __\name\()_proc_info,#object
@@ -514,7 +514,7 @@ __\name\()_proc_info:
        .long   PMD_TYPE_SECT | \
                PMD_SECT_AP_WRITE | \
                PMD_SECT_AP_READ
-       b       __xsc3_setup
+       initfn  __xsc3_setup, __\name\()_proc_info
        .long   cpu_arch_name
        .long   cpu_elf_name
        .long   HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
index afa2b3c4df4a267e5a609c13e6e7d6461be85616..b6bbfdb6dfdc3d1681a562ef4eb96f95d33d6b03 100644 (file)
@@ -612,7 +612,7 @@ xscale_crval:
 
        .align
 
-       .section ".proc.info.init", #alloc, #execinstr
+       .section ".proc.info.init", #alloc
 
 .macro xscale_proc_info name:req, cpu_val:req, cpu_mask:req, cpu_name:req, cache
        .type   __\name\()_proc_info,#object
@@ -627,7 +627,7 @@ __\name\()_proc_info:
        .long   PMD_TYPE_SECT | \
                PMD_SECT_AP_WRITE | \
                PMD_SECT_AP_READ
-       b       __xscale_setup
+       initfn  __xscale_setup, __\name\()_proc_info
        .long   cpu_arch_name
        .long   cpu_elf_name
        .long   HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
index 5d65be1f1e8a758b297f142254ad9eeb77146c9d..71df4354765927da922606db930c6665cbd0c7f9 100644 (file)
@@ -113,7 +113,7 @@ next:
        @ to fault.  Emit the appropriate exception gunk to fix things up.
        @ ??? For some reason, faults can happen at .Lx2 even with a
        @ plain LDR instruction.  Weird, but it seems harmless.
-       .pushsection .fixup,"ax"
+       .pushsection .text.fixup,"ax"
        .align  2
 .Lfix: ret     r9                      @ let the user eat segfaults
        .popsection
diff --git a/arch/arm/vdso/.gitignore b/arch/arm/vdso/.gitignore
new file mode 100644 (file)
index 0000000..f8b69d8
--- /dev/null
@@ -0,0 +1 @@
+vdso.lds
diff --git a/arch/arm/vdso/Makefile b/arch/arm/vdso/Makefile
new file mode 100644 (file)
index 0000000..bab0a8b
--- /dev/null
@@ -0,0 +1,74 @@
+hostprogs-y := vdsomunge
+
+obj-vdso := vgettimeofday.o datapage.o
+
+# Build rules
+targets := $(obj-vdso) vdso.so vdso.so.dbg vdso.so.raw vdso.lds
+obj-vdso := $(addprefix $(obj)/, $(obj-vdso))
+
+ccflags-y := -shared -fPIC -fno-common -fno-builtin -fno-stack-protector
+ccflags-y += -nostdlib -Wl,-soname=linux-vdso.so.1 -DDISABLE_BRANCH_PROFILING
+ccflags-y += -Wl,--no-undefined $(call cc-ldoption, -Wl$(comma)--hash-style=sysv)
+
+obj-y += vdso.o
+extra-y += vdso.lds
+CPPFLAGS_vdso.lds += -P -C -U$(ARCH)
+
+CFLAGS_REMOVE_vdso.o = -pg
+
+# Force -O2 to avoid libgcc dependencies
+CFLAGS_REMOVE_vgettimeofday.o = -pg -Os
+CFLAGS_vgettimeofday.o = -O2
+
+# Disable gcov profiling for VDSO code
+GCOV_PROFILE := n
+
+# Force dependency
+$(obj)/vdso.o : $(obj)/vdso.so
+
+# Link rule for the .so file
+$(obj)/vdso.so.raw: $(src)/vdso.lds $(obj-vdso) FORCE
+       $(call if_changed,vdsold)
+
+$(obj)/vdso.so.dbg: $(obj)/vdso.so.raw $(obj)/vdsomunge FORCE
+       $(call if_changed,vdsomunge)
+
+# Strip rule for the .so file
+$(obj)/%.so: OBJCOPYFLAGS := -S
+$(obj)/%.so: $(obj)/%.so.dbg FORCE
+       $(call if_changed,objcopy)
+
+# Actual build commands
+quiet_cmd_vdsold = VDSO    $@
+      cmd_vdsold = $(CC) $(c_flags) -Wl,-T $(filter %.lds,$^) $(filter %.o,$^) \
+                   $(call cc-ldoption, -Wl$(comma)--build-id) \
+                   -Wl,-Bsymbolic -Wl,-z,max-page-size=4096 \
+                   -Wl,-z,common-page-size=4096 -o $@
+
+quiet_cmd_vdsomunge = MUNGE   $@
+      cmd_vdsomunge = $(objtree)/$(obj)/vdsomunge $< $@
+
+#
+# Install the unstripped copy of vdso.so.dbg.  If our toolchain
+# supports build-id, install .build-id links as well.
+#
+# Cribbed from arch/x86/vdso/Makefile.
+#
+quiet_cmd_vdso_install = INSTALL $<
+define cmd_vdso_install
+       cp $< "$(MODLIB)/vdso/vdso.so"; \
+       if readelf -n $< | grep -q 'Build ID'; then \
+         buildid=`readelf -n $< |grep 'Build ID' |sed -e 's/^.*Build ID: \(.*\)$$/\1/'`; \
+         first=`echo $$buildid | cut -b-2`; \
+         last=`echo $$buildid | cut -b3-`; \
+         mkdir -p "$(MODLIB)/vdso/.build-id/$$first"; \
+         ln -sf "../../vdso.so" "$(MODLIB)/vdso/.build-id/$$first/$$last.debug"; \
+       fi
+endef
+
+$(MODLIB)/vdso: FORCE
+       @mkdir -p $(MODLIB)/vdso
+
+PHONY += vdso_install
+vdso_install: $(obj)/vdso.so.dbg $(MODLIB)/vdso FORCE
+       $(call cmd,vdso_install)
diff --git a/arch/arm/vdso/datapage.S b/arch/arm/vdso/datapage.S
new file mode 100644 (file)
index 0000000..a2e6036
--- /dev/null
@@ -0,0 +1,15 @@
+#include <linux/linkage.h>
+#include <asm/asm-offsets.h>
+
+       .align 2
+.L_vdso_data_ptr:
+       .long   _start - . - VDSO_DATA_SIZE
+
+ENTRY(__get_datapage)
+       .fnstart
+       adr     r0, .L_vdso_data_ptr
+       ldr     r1, [r0]
+       add     r0, r0, r1
+       bx      lr
+       .fnend
+ENDPROC(__get_datapage)
diff --git a/arch/arm/vdso/vdso.S b/arch/arm/vdso/vdso.S
new file mode 100644 (file)
index 0000000..b2b97e3
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Adapted from arm64 version.
+ *
+ * Copyright (C) 2012 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Will Deacon <will.deacon@arm.com>
+ */
+
+#include <linux/init.h>
+#include <linux/linkage.h>
+#include <linux/const.h>
+#include <asm/page.h>
+
+       __PAGE_ALIGNED_DATA
+
+       .globl vdso_start, vdso_end
+       .balign PAGE_SIZE
+vdso_start:
+       .incbin "arch/arm/vdso/vdso.so"
+       .balign PAGE_SIZE
+vdso_end:
+
+       .previous
diff --git a/arch/arm/vdso/vdso.lds.S b/arch/arm/vdso/vdso.lds.S
new file mode 100644 (file)
index 0000000..89ca89f
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Adapted from arm64 version.
+ *
+ * GNU linker script for the VDSO library.
+ *
+ * Copyright (C) 2012 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Will Deacon <will.deacon@arm.com>
+ * Heavily based on the vDSO linker scripts for other archs.
+ */
+
+#include <linux/const.h>
+#include <asm/page.h>
+#include <asm/vdso.h>
+
+OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
+OUTPUT_ARCH(arm)
+
+SECTIONS
+{
+       PROVIDE(_start = .);
+
+       . = SIZEOF_HEADERS;
+
+       .hash           : { *(.hash) }                  :text
+       .gnu.hash       : { *(.gnu.hash) }
+       .dynsym         : { *(.dynsym) }
+       .dynstr         : { *(.dynstr) }
+       .gnu.version    : { *(.gnu.version) }
+       .gnu.version_d  : { *(.gnu.version_d) }
+       .gnu.version_r  : { *(.gnu.version_r) }
+
+       .note           : { *(.note.*) }                :text   :note
+
+
+       .eh_frame_hdr   : { *(.eh_frame_hdr) }          :text   :eh_frame_hdr
+       .eh_frame       : { KEEP (*(.eh_frame)) }       :text
+
+       .dynamic        : { *(.dynamic) }               :text   :dynamic
+
+       .rodata         : { *(.rodata*) }               :text
+
+       .text           : { *(.text*) }                 :text   =0xe7f001f2
+
+       .got            : { *(.got) }
+       .rel.plt        : { *(.rel.plt) }
+
+       /DISCARD/       : {
+               *(.note.GNU-stack)
+               *(.data .data.* .gnu.linkonce.d.* .sdata*)
+               *(.bss .sbss .dynbss .dynsbss)
+       }
+}
+
+/*
+ * We must supply the ELF program headers explicitly to get just one
+ * PT_LOAD segment, and set the flags explicitly to make segments read-only.
+ */
+PHDRS
+{
+       text            PT_LOAD         FLAGS(5) FILEHDR PHDRS; /* PF_R|PF_X */
+       dynamic         PT_DYNAMIC      FLAGS(4);               /* PF_R */
+       note            PT_NOTE         FLAGS(4);               /* PF_R */
+       eh_frame_hdr    PT_GNU_EH_FRAME;
+}
+
+VERSION
+{
+       LINUX_2.6 {
+       global:
+               __vdso_clock_gettime;
+               __vdso_gettimeofday;
+       local: *;
+       };
+}
diff --git a/arch/arm/vdso/vdsomunge.c b/arch/arm/vdso/vdsomunge.c
new file mode 100644 (file)
index 0000000..9005b07
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * Copyright 2015 Mentor Graphics Corporation.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * vdsomunge - Host program which produces a shared object
+ * architecturally specified to be usable by both soft- and hard-float
+ * programs.
+ *
+ * The Procedure Call Standard for the ARM Architecture (ARM IHI
+ * 0042E) says:
+ *
+ *     6.4.1 VFP and Base Standard Compatibility
+ *
+ *     Code compiled for the VFP calling standard is compatible with
+ *     the base standard (and vice-versa) if no floating-point or
+ *     containerized vector arguments or results are used.
+ *
+ * And ELF for the ARM Architecture (ARM IHI 0044E) (Table 4-2) says:
+ *
+ *     If both EF_ARM_ABI_FLOAT_XXXX bits are clear, conformance to the
+ *     base procedure-call standard is implied.
+ *
+ * The VDSO is built with -msoft-float, as with the rest of the ARM
+ * kernel, and uses no floating point arguments or results.  The build
+ * process will produce a shared object that may or may not have the
+ * EF_ARM_ABI_FLOAT_SOFT flag set (it seems to depend on the binutils
+ * version; binutils starting with 2.24 appears to set it).  The
+ * EF_ARM_ABI_FLOAT_HARD flag should definitely not be set, and this
+ * program will error out if it is.
+ *
+ * If the soft-float flag is set, this program clears it.  That's all
+ * it does.
+ */
+
+#define _GNU_SOURCE
+
+#include <byteswap.h>
+#include <elf.h>
+#include <errno.h>
+#include <error.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+#define HOST_ORDER ELFDATA2LSB
+#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+#define HOST_ORDER ELFDATA2MSB
+#endif
+
+/* Some of the ELF constants we'd like to use were added to <elf.h>
+ * relatively recently.
+ */
+#ifndef EF_ARM_EABI_VER5
+#define EF_ARM_EABI_VER5 0x05000000
+#endif
+
+#ifndef EF_ARM_ABI_FLOAT_SOFT
+#define EF_ARM_ABI_FLOAT_SOFT 0x200
+#endif
+
+#ifndef EF_ARM_ABI_FLOAT_HARD
+#define EF_ARM_ABI_FLOAT_HARD 0x400
+#endif
+
+static const char *outfile;
+
+static void cleanup(void)
+{
+       if (error_message_count > 0 && outfile != NULL)
+               unlink(outfile);
+}
+
+static Elf32_Word read_elf_word(Elf32_Word word, bool swap)
+{
+       return swap ? bswap_32(word) : word;
+}
+
+static Elf32_Half read_elf_half(Elf32_Half half, bool swap)
+{
+       return swap ? bswap_16(half) : half;
+}
+
+static void write_elf_word(Elf32_Word val, Elf32_Word *dst, bool swap)
+{
+       *dst = swap ? bswap_32(val) : val;
+}
+
+int main(int argc, char **argv)
+{
+       const Elf32_Ehdr *inhdr;
+       bool clear_soft_float;
+       const char *infile;
+       Elf32_Word e_flags;
+       const void *inbuf;
+       struct stat stat;
+       void *outbuf;
+       bool swap;
+       int outfd;
+       int infd;
+
+       atexit(cleanup);
+
+       if (argc != 3)
+               error(EXIT_FAILURE, 0, "Usage: %s [infile] [outfile]", argv[0]);
+
+       infile = argv[1];
+       outfile = argv[2];
+
+       infd = open(infile, O_RDONLY);
+       if (infd < 0)
+               error(EXIT_FAILURE, errno, "Cannot open %s", infile);
+
+       if (fstat(infd, &stat) != 0)
+               error(EXIT_FAILURE, errno, "Failed stat for %s", infile);
+
+       inbuf = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, infd, 0);
+       if (inbuf == MAP_FAILED)
+               error(EXIT_FAILURE, errno, "Failed to map %s", infile);
+
+       close(infd);
+
+       inhdr = inbuf;
+
+       if (memcmp(&inhdr->e_ident, ELFMAG, SELFMAG) != 0)
+               error(EXIT_FAILURE, 0, "Not an ELF file");
+
+       if (inhdr->e_ident[EI_CLASS] != ELFCLASS32)
+               error(EXIT_FAILURE, 0, "Unsupported ELF class");
+
+       swap = inhdr->e_ident[EI_DATA] != HOST_ORDER;
+
+       if (read_elf_half(inhdr->e_type, swap) != ET_DYN)
+               error(EXIT_FAILURE, 0, "Not a shared object");
+
+       if (read_elf_half(inhdr->e_machine, swap) != EM_ARM) {
+               error(EXIT_FAILURE, 0, "Unsupported architecture %#x",
+                     inhdr->e_machine);
+       }
+
+       e_flags = read_elf_word(inhdr->e_flags, swap);
+
+       if (EF_ARM_EABI_VERSION(e_flags) != EF_ARM_EABI_VER5) {
+               error(EXIT_FAILURE, 0, "Unsupported EABI version %#x",
+                     EF_ARM_EABI_VERSION(e_flags));
+       }
+
+       if (e_flags & EF_ARM_ABI_FLOAT_HARD)
+               error(EXIT_FAILURE, 0,
+                     "Unexpected hard-float flag set in e_flags");
+
+       clear_soft_float = !!(e_flags & EF_ARM_ABI_FLOAT_SOFT);
+
+       outfd = open(outfile, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
+       if (outfd < 0)
+               error(EXIT_FAILURE, errno, "Cannot open %s", outfile);
+
+       if (ftruncate(outfd, stat.st_size) != 0)
+               error(EXIT_FAILURE, errno, "Cannot truncate %s", outfile);
+
+       outbuf = mmap(NULL, stat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED,
+                     outfd, 0);
+       if (outbuf == MAP_FAILED)
+               error(EXIT_FAILURE, errno, "Failed to map %s", outfile);
+
+       close(outfd);
+
+       memcpy(outbuf, inbuf, stat.st_size);
+
+       if (clear_soft_float) {
+               Elf32_Ehdr *outhdr;
+
+               outhdr = outbuf;
+               e_flags &= ~EF_ARM_ABI_FLOAT_SOFT;
+               write_elf_word(e_flags, &outhdr->e_flags, swap);
+       }
+
+       if (msync(outbuf, stat.st_size, MS_SYNC) != 0)
+               error(EXIT_FAILURE, errno, "Failed to sync %s", outfile);
+
+       return EXIT_SUCCESS;
+}
diff --git a/arch/arm/vdso/vgettimeofday.c b/arch/arm/vdso/vgettimeofday.c
new file mode 100644 (file)
index 0000000..79214d5
--- /dev/null
@@ -0,0 +1,282 @@
+/*
+ * Copyright 2015 Mentor Graphics Corporation.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/compiler.h>
+#include <linux/hrtimer.h>
+#include <linux/time.h>
+#include <asm/arch_timer.h>
+#include <asm/barrier.h>
+#include <asm/bug.h>
+#include <asm/page.h>
+#include <asm/unistd.h>
+#include <asm/vdso_datapage.h>
+
+#ifndef CONFIG_AEABI
+#error This code depends on AEABI system call conventions
+#endif
+
+extern struct vdso_data *__get_datapage(void);
+
+static notrace u32 __vdso_read_begin(const struct vdso_data *vdata)
+{
+       u32 seq;
+repeat:
+       seq = ACCESS_ONCE(vdata->seq_count);
+       if (seq & 1) {
+               cpu_relax();
+               goto repeat;
+       }
+       return seq;
+}
+
+static notrace u32 vdso_read_begin(const struct vdso_data *vdata)
+{
+       u32 seq;
+
+       seq = __vdso_read_begin(vdata);
+
+       smp_rmb(); /* Pairs with smp_wmb in vdso_write_end */
+       return seq;
+}
+
+static notrace int vdso_read_retry(const struct vdso_data *vdata, u32 start)
+{
+       smp_rmb(); /* Pairs with smp_wmb in vdso_write_begin */
+       return vdata->seq_count != start;
+}
+
+static notrace long clock_gettime_fallback(clockid_t _clkid,
+                                          struct timespec *_ts)
+{
+       register struct timespec *ts asm("r1") = _ts;
+       register clockid_t clkid asm("r0") = _clkid;
+       register long ret asm ("r0");
+       register long nr asm("r7") = __NR_clock_gettime;
+
+       asm volatile(
+       "       swi #0\n"
+       : "=r" (ret)
+       : "r" (clkid), "r" (ts), "r" (nr)
+       : "memory");
+
+       return ret;
+}
+
+static notrace int do_realtime_coarse(struct timespec *ts,
+                                     struct vdso_data *vdata)
+{
+       u32 seq;
+
+       do {
+               seq = vdso_read_begin(vdata);
+
+               ts->tv_sec = vdata->xtime_coarse_sec;
+               ts->tv_nsec = vdata->xtime_coarse_nsec;
+
+       } while (vdso_read_retry(vdata, seq));
+
+       return 0;
+}
+
+static notrace int do_monotonic_coarse(struct timespec *ts,
+                                      struct vdso_data *vdata)
+{
+       struct timespec tomono;
+       u32 seq;
+
+       do {
+               seq = vdso_read_begin(vdata);
+
+               ts->tv_sec = vdata->xtime_coarse_sec;
+               ts->tv_nsec = vdata->xtime_coarse_nsec;
+
+               tomono.tv_sec = vdata->wtm_clock_sec;
+               tomono.tv_nsec = vdata->wtm_clock_nsec;
+
+       } while (vdso_read_retry(vdata, seq));
+
+       ts->tv_sec += tomono.tv_sec;
+       timespec_add_ns(ts, tomono.tv_nsec);
+
+       return 0;
+}
+
+#ifdef CONFIG_ARM_ARCH_TIMER
+
+static notrace u64 get_ns(struct vdso_data *vdata)
+{
+       u64 cycle_delta;
+       u64 cycle_now;
+       u64 nsec;
+
+       cycle_now = arch_counter_get_cntvct();
+
+       cycle_delta = (cycle_now - vdata->cs_cycle_last) & vdata->cs_mask;
+
+       nsec = (cycle_delta * vdata->cs_mult) + vdata->xtime_clock_snsec;
+       nsec >>= vdata->cs_shift;
+
+       return nsec;
+}
+
+static notrace int do_realtime(struct timespec *ts, struct vdso_data *vdata)
+{
+       u64 nsecs;
+       u32 seq;
+
+       do {
+               seq = vdso_read_begin(vdata);
+
+               if (!vdata->tk_is_cntvct)
+                       return -1;
+
+               ts->tv_sec = vdata->xtime_clock_sec;
+               nsecs = get_ns(vdata);
+
+       } while (vdso_read_retry(vdata, seq));
+
+       ts->tv_nsec = 0;
+       timespec_add_ns(ts, nsecs);
+
+       return 0;
+}
+
+static notrace int do_monotonic(struct timespec *ts, struct vdso_data *vdata)
+{
+       struct timespec tomono;
+       u64 nsecs;
+       u32 seq;
+
+       do {
+               seq = vdso_read_begin(vdata);
+
+               if (!vdata->tk_is_cntvct)
+                       return -1;
+
+               ts->tv_sec = vdata->xtime_clock_sec;
+               nsecs = get_ns(vdata);
+
+               tomono.tv_sec = vdata->wtm_clock_sec;
+               tomono.tv_nsec = vdata->wtm_clock_nsec;
+
+       } while (vdso_read_retry(vdata, seq));
+
+       ts->tv_sec += tomono.tv_sec;
+       ts->tv_nsec = 0;
+       timespec_add_ns(ts, nsecs + tomono.tv_nsec);
+
+       return 0;
+}
+
+#else /* CONFIG_ARM_ARCH_TIMER */
+
+static notrace int do_realtime(struct timespec *ts, struct vdso_data *vdata)
+{
+       return -1;
+}
+
+static notrace int do_monotonic(struct timespec *ts, struct vdso_data *vdata)
+{
+       return -1;
+}
+
+#endif /* CONFIG_ARM_ARCH_TIMER */
+
+notrace int __vdso_clock_gettime(clockid_t clkid, struct timespec *ts)
+{
+       struct vdso_data *vdata;
+       int ret = -1;
+
+       vdata = __get_datapage();
+
+       switch (clkid) {
+       case CLOCK_REALTIME_COARSE:
+               ret = do_realtime_coarse(ts, vdata);
+               break;
+       case CLOCK_MONOTONIC_COARSE:
+               ret = do_monotonic_coarse(ts, vdata);
+               break;
+       case CLOCK_REALTIME:
+               ret = do_realtime(ts, vdata);
+               break;
+       case CLOCK_MONOTONIC:
+               ret = do_monotonic(ts, vdata);
+               break;
+       default:
+               break;
+       }
+
+       if (ret)
+               ret = clock_gettime_fallback(clkid, ts);
+
+       return ret;
+}
+
+static notrace long gettimeofday_fallback(struct timeval *_tv,
+                                         struct timezone *_tz)
+{
+       register struct timezone *tz asm("r1") = _tz;
+       register struct timeval *tv asm("r0") = _tv;
+       register long ret asm ("r0");
+       register long nr asm("r7") = __NR_gettimeofday;
+
+       asm volatile(
+       "       swi #0\n"
+       : "=r" (ret)
+       : "r" (tv), "r" (tz), "r" (nr)
+       : "memory");
+
+       return ret;
+}
+
+notrace int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz)
+{
+       struct timespec ts;
+       struct vdso_data *vdata;
+       int ret;
+
+       vdata = __get_datapage();
+
+       ret = do_realtime(&ts, vdata);
+       if (ret)
+               return gettimeofday_fallback(tv, tz);
+
+       if (tv) {
+               tv->tv_sec = ts.tv_sec;
+               tv->tv_usec = ts.tv_nsec / 1000;
+       }
+       if (tz) {
+               tz->tz_minuteswest = vdata->tz_minuteswest;
+               tz->tz_dsttime = vdata->tz_dsttime;
+       }
+
+       return ret;
+}
+
+/* Avoid unresolved references emitted by GCC */
+
+void __aeabi_unwind_cpp_pr0(void)
+{
+}
+
+void __aeabi_unwind_cpp_pr1(void)
+{
+}
+
+void __aeabi_unwind_cpp_pr2(void)
+{
+}
index c6dc3548e5d1add89bdc06235f2a69707774be5f..b0b688c481e8ae62f3213cb405a74916eabce73e 100644 (file)
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
+#include <linux/of.h>
 
 #include <soc/tegra/ahb.h>
 
 #define DRV_NAME "tegra-ahb"
 
-#define AHB_ARBITRATION_DISABLE                0x00
-#define AHB_ARBITRATION_PRIORITY_CTRL  0x04
+#define AHB_ARBITRATION_DISABLE                0x04
+#define AHB_ARBITRATION_PRIORITY_CTRL  0x08
 #define   AHB_PRIORITY_WEIGHT(x)       (((x) & 0x7) << 29)
 #define   PRIORITY_SELECT_USB BIT(6)
 #define   PRIORITY_SELECT_USB2 BIT(18)
 #define   PRIORITY_SELECT_USB3 BIT(17)
 
-#define AHB_GIZMO_AHB_MEM              0x0c
+#define AHB_GIZMO_AHB_MEM              0x10
 #define   ENB_FAST_REARBITRATE BIT(2)
 #define   DONT_SPLIT_AHB_WR     BIT(7)
 
-#define AHB_GIZMO_APB_DMA              0x10
-#define AHB_GIZMO_IDE                  0x18
-#define AHB_GIZMO_USB                  0x1c
-#define AHB_GIZMO_AHB_XBAR_BRIDGE      0x20
-#define AHB_GIZMO_CPU_AHB_BRIDGE       0x24
-#define AHB_GIZMO_COP_AHB_BRIDGE       0x28
-#define AHB_GIZMO_XBAR_APB_CTLR                0x2c
-#define AHB_GIZMO_VCP_AHB_BRIDGE       0x30
-#define AHB_GIZMO_NAND                 0x3c
-#define AHB_GIZMO_SDMMC4               0x44
-#define AHB_GIZMO_XIO                  0x48
-#define AHB_GIZMO_BSEV                 0x60
-#define AHB_GIZMO_BSEA                 0x70
-#define AHB_GIZMO_NOR                  0x74
-#define AHB_GIZMO_USB2                 0x78
-#define AHB_GIZMO_USB3                 0x7c
+#define AHB_GIZMO_APB_DMA              0x14
+#define AHB_GIZMO_IDE                  0x1c
+#define AHB_GIZMO_USB                  0x20
+#define AHB_GIZMO_AHB_XBAR_BRIDGE      0x24
+#define AHB_GIZMO_CPU_AHB_BRIDGE       0x28
+#define AHB_GIZMO_COP_AHB_BRIDGE       0x2c
+#define AHB_GIZMO_XBAR_APB_CTLR                0x30
+#define AHB_GIZMO_VCP_AHB_BRIDGE       0x34
+#define AHB_GIZMO_NAND                 0x40
+#define AHB_GIZMO_SDMMC4               0x48
+#define AHB_GIZMO_XIO                  0x4c
+#define AHB_GIZMO_BSEV                 0x64
+#define AHB_GIZMO_BSEA                 0x74
+#define AHB_GIZMO_NOR                  0x78
+#define AHB_GIZMO_USB2                 0x7c
+#define AHB_GIZMO_USB3                 0x80
 #define   IMMEDIATE    BIT(18)
 
-#define AHB_GIZMO_SDMMC1               0x80
-#define AHB_GIZMO_SDMMC2               0x84
-#define AHB_GIZMO_SDMMC3               0x88
-#define AHB_MEM_PREFETCH_CFG_X         0xd8
-#define AHB_ARBITRATION_XBAR_CTRL      0xdc
-#define AHB_MEM_PREFETCH_CFG3          0xe0
-#define AHB_MEM_PREFETCH_CFG4          0xe4
-#define AHB_MEM_PREFETCH_CFG1          0xec
-#define AHB_MEM_PREFETCH_CFG2          0xf0
+#define AHB_GIZMO_SDMMC1               0x84
+#define AHB_GIZMO_SDMMC2               0x88
+#define AHB_GIZMO_SDMMC3               0x8c
+#define AHB_MEM_PREFETCH_CFG_X         0xdc
+#define AHB_ARBITRATION_XBAR_CTRL      0xe0
+#define AHB_MEM_PREFETCH_CFG3          0xe4
+#define AHB_MEM_PREFETCH_CFG4          0xe8
+#define AHB_MEM_PREFETCH_CFG1          0xf0
+#define AHB_MEM_PREFETCH_CFG2          0xf4
 #define   PREFETCH_ENB BIT(31)
 #define   MST_ID(x)    (((x) & 0x1f) << 26)
 #define   AHBDMA_MST_ID        MST_ID(5)
 #define   ADDR_BNDRY(x)        (((x) & 0xf) << 21)
 #define   INACTIVITY_TIMEOUT(x)        (((x) & 0xffff) << 0)
 
-#define AHB_ARBITRATION_AHB_MEM_WRQUE_MST_ID   0xf8
+#define AHB_ARBITRATION_AHB_MEM_WRQUE_MST_ID   0xfc
 
 #define AHB_ARBITRATION_XBAR_CTRL_SMMU_INIT_DONE BIT(17)
 
+/*
+ * INCORRECT_BASE_ADDR_LOW_BYTE: Legacy kernel DT files for Tegra SoCs
+ * prior to Tegra124 generally use a physical base address ending in
+ * 0x4 for the AHB IP block.  According to the TRM, the low byte
+ * should be 0x0.  During device probing, this macro is used to detect
+ * whether the passed-in physical address is incorrect, and if so, to
+ * correct it.
+ */
+#define INCORRECT_BASE_ADDR_LOW_BYTE           0x4
+
 static struct platform_driver tegra_ahb_driver;
 
 static const u32 tegra_ahb_gizmo[] = {
@@ -257,6 +268,15 @@ static int tegra_ahb_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+       /* Correct the IP block base address if necessary */
+       if (res &&
+           (res->start & INCORRECT_BASE_ADDR_LOW_BYTE) ==
+           INCORRECT_BASE_ADDR_LOW_BYTE) {
+               dev_warn(&pdev->dev, "incorrect AHB base address in DT data - enabling workaround\n");
+               res->start -= INCORRECT_BASE_ADDR_LOW_BYTE;
+       }
+
        ahb->regs = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(ahb->regs))
                return PTR_ERR(ahb->regs);
index ac78910d7416c5f7f2a68cfbde0d950d58ab0d9c..463231d5bfc79c3528c880e1b18554d6d4769fb7 100644 (file)
 #define TEXT_TEXT                                                      \
                ALIGN_FUNCTION();                                       \
                *(.text.hot)                                            \
-               *(.text)                                                \
+               *(.text .text.fixup)                                    \
                *(.ref.text)                                            \
        MEM_KEEP(init.text)                                             \
        MEM_KEEP(exit.text)                                             \