Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 24 Oct 2018 05:42:00 +0000 (06:42 +0100)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 24 Oct 2018 05:42:00 +0000 (06:42 +0100)
Pull sparc updates from David Miller:
 "Mostly VDSO cleanups and optimizations"

* git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc:
  sparc: Several small VDSO vclock_gettime.c improvements.
  sparc: Validate VDSO for undefined symbols.
  sparc: Really use linker with LDFLAGS.
  sparc: Improve VDSO CFLAGS.
  sparc: Set DISABLE_BRANCH_PROFILING in VDSO CFLAGS.
  sparc: Don't bother masking out TICK_PRIV_BIT in VDSO code.
  sparc: Inline VDSO gettime code aggressively.
  sparc: Improve VDSO instruction patching.
  sparc: Fix parport build warnings.

arch/sparc/include/asm/parport.h
arch/sparc/include/asm/thread_info_64.h
arch/sparc/include/asm/vdso.h
arch/sparc/kernel/time_64.c
arch/sparc/vdso/Makefile
arch/sparc/vdso/checkundef.sh [new file with mode: 0644]
arch/sparc/vdso/vclock_gettime.c
arch/sparc/vdso/vdso-layout.lds.S
arch/sparc/vdso/vdso2c.c
arch/sparc/vdso/vdso2c.h
arch/sparc/vdso/vma.c

index 05df5f0430535f307495662610f2c06dda92d0b5..3c5a1c620f0f7759aa1af38c889078ddb77da2b2 100644 (file)
@@ -21,6 +21,7 @@
  */
 #define HAS_DMA
 
+#ifdef CONFIG_PARPORT_PC_FIFO
 static DEFINE_SPINLOCK(dma_spin_lock);
 
 #define claim_dma_lock() \
@@ -31,6 +32,7 @@ static DEFINE_SPINLOCK(dma_spin_lock);
 
 #define release_dma_lock(__flags) \
        spin_unlock_irqrestore(&dma_spin_lock, __flags);
+#endif
 
 static struct sparc_ebus_info {
        struct ebus_dma_info info;
index 7fb67636092893dbacd13a3e596484fa3cf4b5d0..20255471e653d450b22ea149ba256651175915b9 100644 (file)
@@ -121,8 +121,12 @@ struct thread_info {
 }
 
 /* how to get the thread information struct from C */
+#ifndef BUILD_VDSO
 register struct thread_info *current_thread_info_reg asm("g6");
 #define current_thread_info()  (current_thread_info_reg)
+#else
+extern struct thread_info *current_thread_info(void);
+#endif
 
 /* thread information allocation */
 #if PAGE_SHIFT == 13
index 93b628731a5eac632ec11c3711ad4f321afe49c1..56836eb0178737e5af6c7b6d7db695a007870317 100644 (file)
@@ -8,10 +8,10 @@
 struct vdso_image {
        void *data;
        unsigned long size;   /* Always a multiple of PAGE_SIZE */
+
+       unsigned long tick_patch, tick_patch_len;
+
        long sym_vvar_start;  /* Negative offset to the vvar area */
-       long sym_vread_tick; /* Start of vread_tick section */
-       long sym_vread_tick_patch_start; /* Start of tick read */
-       long sym_vread_tick_patch_end;   /* End of tick read */
 };
 
 #ifdef CONFIG_SPARC64
index f0eba72aa1ad692c124b608f5314e8a0ef96f3e1..5f356dc8e1782c815af46c260f3bfcb7d2fe68a1 100644 (file)
@@ -53,8 +53,6 @@
 
 DEFINE_SPINLOCK(rtc_lock);
 
-unsigned int __read_mostly vdso_fix_stick;
-
 #ifdef CONFIG_SMP
 unsigned long profile_pc(struct pt_regs *regs)
 {
@@ -838,7 +836,6 @@ void __init time_init_early(void)
                } else {
                        init_tick_ops(&tick_operations);
                        clocksource_tick.archdata.vclock_mode = VCLOCK_TICK;
-                       vdso_fix_stick = 1;
                }
        } else {
                init_tick_ops(&stick_operations);
index dc85570d88395a411842c7d419a0f2d2fb200914..a6e18ca4cc18ce25fe87135b3034588c25fbee36 100644 (file)
@@ -33,10 +33,8 @@ targets += $(vdso_img_sodbg) $(vdso_img-y:%=vdso%.so)
 
 CPPFLAGS_vdso.lds += -P -C
 
-VDSO_LDFLAGS_vdso.lds = -m64 -Wl,-soname=linux-vdso.so.1 \
-                       -Wl,--no-undefined \
-                       -Wl,-z,max-page-size=8192 -Wl,-z,common-page-size=8192 \
-                       $(DISABLE_LTO)
+VDSO_LDFLAGS_vdso.lds = -m elf64_sparc -soname linux-vdso.so.1 --no-undefined \
+                       -z max-page-size=8192 -z common-page-size=8192
 
 $(obj)/vdso64.so.dbg: $(obj)/vdso.lds $(vobjs) FORCE
        $(call if_changed,vdso)
@@ -54,13 +52,14 @@ $(obj)/vdso-image-%.c: $(obj)/vdso%.so.dbg $(obj)/vdso%.so $(obj)/vdso2c FORCE
 # Don't omit frame pointers for ease of userspace debugging, but do
 # optimize sibling calls.
 #
-CFL := $(PROFILING) -mcmodel=medlow -fPIC -O2 -fasynchronous-unwind-tables \
-       -m64 -ffixed-g2 -ffixed-g3 -fcall-used-g4 -fcall-used-g5 -ffixed-g6 \
-       -ffixed-g7 $(filter -g%,$(KBUILD_CFLAGS)) \
-       $(call cc-option, -fno-stack-protector) -fno-omit-frame-pointer \
-       -foptimize-sibling-calls -DBUILD_VDSO
+CFL := $(PROFILING) -mcmodel=medlow -fPIC -O2 -fasynchronous-unwind-tables -m64 \
+       $(filter -g%,$(KBUILD_CFLAGS)) $(call cc-option, -fno-stack-protector) \
+       -fno-omit-frame-pointer -foptimize-sibling-calls \
+       -DDISABLE_BRANCH_PROFILING -DBUILD_VDSO
 
-$(vobjs): KBUILD_CFLAGS += $(CFL)
+SPARC_REG_CFLAGS = -ffixed-g4 -ffixed-g5 -fcall-used-g5 -fcall-used-g7
+
+$(vobjs): KBUILD_CFLAGS := $(filter-out $(GCC_PLUGINS_CFLAGS) $(SPARC_REG_CFLAGS),$(KBUILD_CFLAGS)) $(CFL)
 
 #
 # vDSO code runs in userspace and -pg doesn't help with profiling anyway.
@@ -73,7 +72,7 @@ $(obj)/%.so: $(obj)/%.so.dbg
        $(call if_changed,objcopy)
 
 CPPFLAGS_vdso32.lds = $(CPPFLAGS_vdso.lds)
-VDSO_LDFLAGS_vdso32.lds = -m32 -Wl,-m,elf32_sparc,-soname=linux-gate.so.1
+VDSO_LDFLAGS_vdso32.lds = -m elf32_sparc -soname linux-gate.so.1
 
 #This makes sure the $(obj) subdirectory exists even though vdso32/
 #is not a kbuild sub-make subdirectory
@@ -91,7 +90,8 @@ KBUILD_CFLAGS_32 := $(filter-out -m64,$(KBUILD_CFLAGS))
 KBUILD_CFLAGS_32 := $(filter-out -mcmodel=medlow,$(KBUILD_CFLAGS_32))
 KBUILD_CFLAGS_32 := $(filter-out -fno-pic,$(KBUILD_CFLAGS_32))
 KBUILD_CFLAGS_32 := $(filter-out $(GCC_PLUGINS_CFLAGS),$(KBUILD_CFLAGS_32))
-KBUILD_CFLAGS_32 += -m32 -msoft-float -fpic -mno-app-regs -ffixed-g7
+KBUILD_CFLAGS_32 := $(filter-out $(SPARC_REG_CFLAGS),$(KBUILD_CFLAGS_32))
+KBUILD_CFLAGS_32 += -m32 -msoft-float -fpic
 KBUILD_CFLAGS_32 += $(call cc-option, -fno-stack-protector)
 KBUILD_CFLAGS_32 += $(call cc-option, -foptimize-sibling-calls)
 KBUILD_CFLAGS_32 += -fno-omit-frame-pointer
@@ -109,12 +109,13 @@ $(obj)/vdso32.so.dbg: FORCE \
 # The DSO images are built using a special linker script.
 #
 quiet_cmd_vdso = VDSO    $@
-      cmd_vdso = $(CC) -nostdlib -o $@ \
+      cmd_vdso = $(LD) -nostdlib -o $@ \
                       $(VDSO_LDFLAGS) $(VDSO_LDFLAGS_$(filter %.lds,$(^F))) \
-                      -Wl,-T,$(filter %.lds,$^) $(filter %.o,$^)
+                      -T $(filter %.lds,$^) $(filter %.o,$^) && \
+               sh $(srctree)/$(src)/checkundef.sh '$(OBJDUMP)' '$@'
 
-VDSO_LDFLAGS = -fPIC -shared $(call cc-ldoption, -Wl$(comma)--hash-style=sysv) \
-       $(call cc-ldoption, -Wl$(comma)--build-id) -Wl,-Bsymbolic
+VDSO_LDFLAGS = -shared $(call ld-option, --hash-style=both) \
+       $(call ld-option, --build-id) -Bsymbolic
 GCOV_PROFILE := n
 
 #
diff --git a/arch/sparc/vdso/checkundef.sh b/arch/sparc/vdso/checkundef.sh
new file mode 100644 (file)
index 0000000..2d85876
--- /dev/null
@@ -0,0 +1,10 @@
+#!/bin/sh
+objdump="$1"
+file="$2"
+$objdump -t "$file" | grep '*UUND*' | grep -v '#scratch' > /dev/null 2>&1
+if [ $? -eq 1 ]; then
+    exit 0
+else
+    echo "$file: undefined symbols found" >&2
+    exit 1
+fi
index 75dca9aab737c6cb43cda34d098a7ad005d552e8..7b539ceebe13a189b6b09a877bae3d0cbacce0f3 100644 (file)
  * Copyright (c) 2017 Oracle and/or its affiliates. All rights reserved.
  */
 
-/* Disable profiling for userspace code: */
-#ifndef        DISABLE_BRANCH_PROFILING
-#define        DISABLE_BRANCH_PROFILING
-#endif
-
 #include <linux/kernel.h>
 #include <linux/time.h>
 #include <linux/string.h>
 #include <asm/clocksource.h>
 #include <asm/vvar.h>
 
-#undef TICK_PRIV_BIT
-#ifdef CONFIG_SPARC64
-#define        TICK_PRIV_BIT   (1UL << 63)
-#else
-#define        TICK_PRIV_BIT   (1ULL << 63)
-#endif
-
 #ifdef CONFIG_SPARC64
 #define SYSCALL_STRING                                                 \
        "ta     0x6d;"                                                  \
  * Compute the vvar page's address in the process address space, and return it
  * as a pointer to the vvar_data.
  */
-static notrace noinline struct vvar_data *
-get_vvar_data(void)
+notrace static __always_inline struct vvar_data *get_vvar_data(void)
 {
        unsigned long ret;
 
        /*
-        * vdso data page is the first vDSO page so grab the return address
+        * vdso data page is the first vDSO page so grab the PC
         * and move up a page to get to the data page.
         */
-       ret = (unsigned long)__builtin_return_address(0);
+       __asm__("rd %%pc, %0" : "=r" (ret));
        ret &= ~(8192 - 1);
        ret -= 8192;
 
        return (struct vvar_data *) ret;
 }
 
-static notrace long
-vdso_fallback_gettime(long clock, struct timespec *ts)
+notrace static long vdso_fallback_gettime(long clock, struct timespec *ts)
 {
        register long num __asm__("g1") = __NR_clock_gettime;
        register long o0 __asm__("o0") = clock;
@@ -88,8 +74,7 @@ vdso_fallback_gettime(long clock, struct timespec *ts)
        return o0;
 }
 
-static notrace __always_inline long
-vdso_fallback_gettimeofday(struct timeval *tv, struct timezone *tz)
+notrace static long vdso_fallback_gettimeofday(struct timeval *tv, struct timezone *tz)
 {
        register long num __asm__("g1") = __NR_gettimeofday;
        register long o0 __asm__("o0") = (long) tv;
@@ -101,38 +86,43 @@ vdso_fallback_gettimeofday(struct timeval *tv, struct timezone *tz)
 }
 
 #ifdef CONFIG_SPARC64
-static notrace noinline u64
-vread_tick(void) {
+notrace static __always_inline u64 vread_tick(void)
+{
        u64     ret;
 
-       __asm__ __volatile__("rd        %%asr24, %0 \n"
-                            ".section  .vread_tick_patch, \"ax\" \n"
-                            "rd        %%tick, %0 \n"
-                            ".previous \n"
-                            : "=&r" (ret));
-       return ret & ~TICK_PRIV_BIT;
+       __asm__ __volatile__("1:\n\t"
+                            "rd                %%tick, %0\n\t"
+                            ".pushsection      .tick_patch, \"a\"\n\t"
+                            ".word             1b - ., 1f - .\n\t"
+                            ".popsection\n\t"
+                            ".pushsection      .tick_patch_replacement, \"ax\"\n\t"
+                            "1:\n\t"
+                            "rd                %%asr24, %0\n\t"
+                            ".popsection\n"
+                            : "=r" (ret));
+       return ret;
 }
 #else
-static notrace noinline u64
-vread_tick(void)
+notrace static __always_inline u64 vread_tick(void)
 {
-       unsigned int lo, hi;
-
-       __asm__ __volatile__("rd        %%asr24, %%g1\n\t"
-                            "srlx      %%g1, 32, %1\n\t"
-                            "srl       %%g1, 0, %0\n"
-                            ".section  .vread_tick_patch, \"ax\" \n"
-                            "rd        %%tick, %%g1\n"
-                            ".previous \n"
-                            : "=&r" (lo), "=&r" (hi)
-                            :
-                            : "g1");
-       return lo | ((u64)hi << 32);
+       register unsigned long long ret asm("o4");
+
+       __asm__ __volatile__("1:\n\t"
+                            "rd                %%tick, %L0\n\t"
+                            "srlx              %L0, 32, %H0\n\t"
+                            ".pushsection      .tick_patch, \"a\"\n\t"
+                            ".word             1b - ., 1f - .\n\t"
+                            ".popsection\n\t"
+                            ".pushsection      .tick_patch_replacement, \"ax\"\n\t"
+                            "1:\n\t"
+                            "rd                %%asr24, %L0\n\t"
+                            ".popsection\n"
+                            : "=r" (ret));
+       return ret;
 }
 #endif
 
-static notrace inline u64
-vgetsns(struct vvar_data *vvar)
+notrace static __always_inline u64 vgetsns(struct vvar_data *vvar)
 {
        u64 v;
        u64 cycles;
@@ -142,13 +132,12 @@ vgetsns(struct vvar_data *vvar)
        return v * vvar->clock.mult;
 }
 
-static notrace noinline int
-do_realtime(struct vvar_data *vvar, struct timespec *ts)
+notrace static __always_inline int do_realtime(struct vvar_data *vvar,
+                                              struct timespec *ts)
 {
        unsigned long seq;
        u64 ns;
 
-       ts->tv_nsec = 0;
        do {
                seq = vvar_read_begin(vvar);
                ts->tv_sec = vvar->wall_time_sec;
@@ -157,18 +146,18 @@ do_realtime(struct vvar_data *vvar, struct timespec *ts)
                ns >>= vvar->clock.shift;
        } while (unlikely(vvar_read_retry(vvar, seq)));
 
-       timespec_add_ns(ts, ns);
+       ts->tv_sec += __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns);
+       ts->tv_nsec = ns;
 
        return 0;
 }
 
-static notrace noinline int
-do_monotonic(struct vvar_data *vvar, struct timespec *ts)
+notrace static __always_inline int do_monotonic(struct vvar_data *vvar,
+                                               struct timespec *ts)
 {
        unsigned long seq;
        u64 ns;
 
-       ts->tv_nsec = 0;
        do {
                seq = vvar_read_begin(vvar);
                ts->tv_sec = vvar->monotonic_time_sec;
@@ -177,13 +166,14 @@ do_monotonic(struct vvar_data *vvar, struct timespec *ts)
                ns >>= vvar->clock.shift;
        } while (unlikely(vvar_read_retry(vvar, seq)));
 
-       timespec_add_ns(ts, ns);
+       ts->tv_sec += __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns);
+       ts->tv_nsec = ns;
 
        return 0;
 }
 
-static notrace noinline int
-do_realtime_coarse(struct vvar_data *vvar, struct timespec *ts)
+notrace static int do_realtime_coarse(struct vvar_data *vvar,
+                                     struct timespec *ts)
 {
        unsigned long seq;
 
@@ -195,8 +185,8 @@ do_realtime_coarse(struct vvar_data *vvar, struct timespec *ts)
        return 0;
 }
 
-static notrace noinline int
-do_monotonic_coarse(struct vvar_data *vvar, struct timespec *ts)
+notrace static int do_monotonic_coarse(struct vvar_data *vvar,
+                                      struct timespec *ts)
 {
        unsigned long seq;
 
index f2c83abaca121d45c9ab94d55d4fa7e50b075f5c..ed36d49e1617a4f055a1d7e646b37a3637580e29 100644 (file)
@@ -73,11 +73,8 @@ SECTIONS
 
        .text           : { *(.text*) }                 :text   =0x90909090,
 
-       .vread_tick_patch : {
-               vread_tick_patch_start = .;
-               *(.vread_tick_patch)
-               vread_tick_patch_end = .;
-       }
+       .tick_patch       : { *(.tick_patch) }          :text
+       .tick_patch_insns : { *(.tick_patch_insns) }    :text
 
        /DISCARD/ : {
                *(.discard)
index 9f5b1cd6d51da64db03c77dc2b3709a41db133fd..ab7504176a7fe800798eebf549019c90575d337d 100644 (file)
@@ -63,9 +63,6 @@ enum {
        sym_vvar_start,
        sym_VDSO_FAKE_SECTION_TABLE_START,
        sym_VDSO_FAKE_SECTION_TABLE_END,
-       sym_vread_tick,
-       sym_vread_tick_patch_start,
-       sym_vread_tick_patch_end
 };
 
 struct vdso_sym {
@@ -81,9 +78,6 @@ struct vdso_sym required_syms[] = {
        [sym_VDSO_FAKE_SECTION_TABLE_END] = {
                "VDSO_FAKE_SECTION_TABLE_END", 0
        },
-       [sym_vread_tick] = {"vread_tick", 1},
-       [sym_vread_tick_patch_start] = {"vread_tick_patch_start", 1},
-       [sym_vread_tick_patch_end] = {"vread_tick_patch_end", 1}
 };
 
 __attribute__((format(printf, 1, 2))) __attribute__((noreturn))
index 808decb0f7bebe95a85337ddd330e7520efaf552..4df005cf98c0e5f4c0e84c68058b8a829e3cdc0b 100644 (file)
@@ -17,10 +17,11 @@ static void BITSFUNC(go)(void *raw_addr, size_t raw_len,
        unsigned long mapping_size;
        int i;
        unsigned long j;
-
-       ELF(Shdr) *symtab_hdr = NULL, *strtab_hdr;
+       ELF(Shdr) *symtab_hdr = NULL, *strtab_hdr, *secstrings_hdr,
+               *patch_sec = NULL;
        ELF(Ehdr) *hdr = (ELF(Ehdr) *)raw_addr;
        ELF(Dyn) *dyn = 0, *dyn_end = 0;
+       const char *secstrings;
        INT_BITS syms[NSYMS] = {};
 
        ELF(Phdr) *pt = (ELF(Phdr) *)(raw_addr + GET_BE(&hdr->e_phoff));
@@ -63,11 +64,18 @@ static void BITSFUNC(go)(void *raw_addr, size_t raw_len,
        }
 
        /* Walk the section table */
+       secstrings_hdr = raw_addr + GET_BE(&hdr->e_shoff) +
+               GET_BE(&hdr->e_shentsize)*GET_BE(&hdr->e_shstrndx);
+       secstrings = raw_addr + GET_BE(&secstrings_hdr->sh_offset);
        for (i = 0; i < GET_BE(&hdr->e_shnum); i++) {
                ELF(Shdr) *sh = raw_addr + GET_BE(&hdr->e_shoff) +
                        GET_BE(&hdr->e_shentsize) * i;
                if (GET_BE(&sh->sh_type) == SHT_SYMTAB)
                        symtab_hdr = sh;
+
+               if (!strcmp(secstrings + GET_BE(&sh->sh_name),
+                           ".tick_patch"))
+                       patch_sec = sh;
        }
 
        if (!symtab_hdr)
@@ -134,6 +142,12 @@ static void BITSFUNC(go)(void *raw_addr, size_t raw_len,
        fprintf(outfile, "const struct vdso_image %s_builtin = {\n", name);
        fprintf(outfile, "\t.data = raw_data,\n");
        fprintf(outfile, "\t.size = %lu,\n", mapping_size);
+       if (patch_sec) {
+               fprintf(outfile, "\t.tick_patch = %lu,\n",
+                       (unsigned long)GET_BE(&patch_sec->sh_offset));
+               fprintf(outfile, "\t.tick_patch_len = %lu,\n",
+                       (unsigned long)GET_BE(&patch_sec->sh_size));
+       }
        for (i = 0; i < NSYMS; i++) {
                if (required_syms[i].export && syms[i])
                        fprintf(outfile, "\t.sym_%s = %" PRIi64 ",\n",
index 5eaff3c1aa0c73110ba0668709b6da5c5fd87736..8874a27d8adcc21062f26477cd212285ff43ea4c 100644 (file)
@@ -16,6 +16,8 @@
 #include <linux/linkage.h>
 #include <linux/random.h>
 #include <linux/elf.h>
+#include <asm/cacheflush.h>
+#include <asm/spitfire.h>
 #include <asm/vdso.h>
 #include <asm/vvar.h>
 #include <asm/page.h>
@@ -40,7 +42,25 @@ static struct vm_special_mapping vdso_mapping32 = {
 
 struct vvar_data *vvar_data;
 
-#define        SAVE_INSTR_SIZE 4
+struct tick_patch_entry {
+       s32 orig, repl;
+};
+
+static void stick_patch(const struct vdso_image *image)
+{
+       struct tick_patch_entry *p, *p_end;
+
+       p = image->data + image->tick_patch;
+       p_end = (void *)p + image->tick_patch_len;
+       while (p < p_end) {
+               u32 *instr = (void *)&p->orig + p->orig;
+               u32 *repl = (void *)&p->repl + p->repl;
+
+               *instr = *repl;
+               flushi(instr);
+               p++;
+       }
+}
 
 /*
  * Allocate pages for the vdso and vvar, and copy in the vdso text from the
@@ -68,21 +88,8 @@ int __init init_vdso_image(const struct vdso_image *image,
        if (!cpp)
                goto oom;
 
-       if (vdso_fix_stick) {
-               /*
-                * If the system uses %tick instead of %stick, patch the VDSO
-                * with instruction reading %tick instead of %stick.
-                */
-               unsigned int j, k = SAVE_INSTR_SIZE;
-               unsigned char *data = image->data;
-
-               for (j = image->sym_vread_tick_patch_start;
-                    j < image->sym_vread_tick_patch_end; j++) {
-
-                       data[image->sym_vread_tick + k] = data[j];
-                       k++;
-               }
-       }
+       if (tlb_type != spitfire)
+               stick_patch(image);
 
        for (i = 0; i < cnpages; i++) {
                cp = alloc_page(GFP_KERNEL);