Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc

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.

+122 -106
+2
arch/sparc/include/asm/parport.h
··· 21 21 */ 22 22 #define HAS_DMA 23 23 24 + #ifdef CONFIG_PARPORT_PC_FIFO 24 25 static DEFINE_SPINLOCK(dma_spin_lock); 25 26 26 27 #define claim_dma_lock() \ ··· 32 31 33 32 #define release_dma_lock(__flags) \ 34 33 spin_unlock_irqrestore(&dma_spin_lock, __flags); 34 + #endif 35 35 36 36 static struct sparc_ebus_info { 37 37 struct ebus_dma_info info;
+4
arch/sparc/include/asm/thread_info_64.h
··· 121 121 } 122 122 123 123 /* how to get the thread information struct from C */ 124 + #ifndef BUILD_VDSO 124 125 register struct thread_info *current_thread_info_reg asm("g6"); 125 126 #define current_thread_info() (current_thread_info_reg) 127 + #else 128 + extern struct thread_info *current_thread_info(void); 129 + #endif 126 130 127 131 /* thread information allocation */ 128 132 #if PAGE_SHIFT == 13
+3 -3
arch/sparc/include/asm/vdso.h
··· 8 8 struct vdso_image { 9 9 void *data; 10 10 unsigned long size; /* Always a multiple of PAGE_SIZE */ 11 + 12 + unsigned long tick_patch, tick_patch_len; 13 + 11 14 long sym_vvar_start; /* Negative offset to the vvar area */ 12 - long sym_vread_tick; /* Start of vread_tick section */ 13 - long sym_vread_tick_patch_start; /* Start of tick read */ 14 - long sym_vread_tick_patch_end; /* End of tick read */ 15 15 }; 16 16 17 17 #ifdef CONFIG_SPARC64
-3
arch/sparc/kernel/time_64.c
··· 53 53 54 54 DEFINE_SPINLOCK(rtc_lock); 55 55 56 - unsigned int __read_mostly vdso_fix_stick; 57 - 58 56 #ifdef CONFIG_SMP 59 57 unsigned long profile_pc(struct pt_regs *regs) 60 58 { ··· 836 838 } else { 837 839 init_tick_ops(&tick_operations); 838 840 clocksource_tick.archdata.vclock_mode = VCLOCK_TICK; 839 - vdso_fix_stick = 1; 840 841 } 841 842 } else { 842 843 init_tick_ops(&stick_operations);
+17 -16
arch/sparc/vdso/Makefile
··· 33 33 34 34 CPPFLAGS_vdso.lds += -P -C 35 35 36 - VDSO_LDFLAGS_vdso.lds = -m64 -Wl,-soname=linux-vdso.so.1 \ 37 - -Wl,--no-undefined \ 38 - -Wl,-z,max-page-size=8192 -Wl,-z,common-page-size=8192 \ 39 - $(DISABLE_LTO) 36 + VDSO_LDFLAGS_vdso.lds = -m elf64_sparc -soname linux-vdso.so.1 --no-undefined \ 37 + -z max-page-size=8192 -z common-page-size=8192 40 38 41 39 $(obj)/vdso64.so.dbg: $(obj)/vdso.lds $(vobjs) FORCE 42 40 $(call if_changed,vdso) ··· 52 54 # Don't omit frame pointers for ease of userspace debugging, but do 53 55 # optimize sibling calls. 54 56 # 55 - CFL := $(PROFILING) -mcmodel=medlow -fPIC -O2 -fasynchronous-unwind-tables \ 56 - -m64 -ffixed-g2 -ffixed-g3 -fcall-used-g4 -fcall-used-g5 -ffixed-g6 \ 57 - -ffixed-g7 $(filter -g%,$(KBUILD_CFLAGS)) \ 58 - $(call cc-option, -fno-stack-protector) -fno-omit-frame-pointer \ 59 - -foptimize-sibling-calls -DBUILD_VDSO 57 + CFL := $(PROFILING) -mcmodel=medlow -fPIC -O2 -fasynchronous-unwind-tables -m64 \ 58 + $(filter -g%,$(KBUILD_CFLAGS)) $(call cc-option, -fno-stack-protector) \ 59 + -fno-omit-frame-pointer -foptimize-sibling-calls \ 60 + -DDISABLE_BRANCH_PROFILING -DBUILD_VDSO 60 61 61 - $(vobjs): KBUILD_CFLAGS += $(CFL) 62 + SPARC_REG_CFLAGS = -ffixed-g4 -ffixed-g5 -fcall-used-g5 -fcall-used-g7 63 + 64 + $(vobjs): KBUILD_CFLAGS := $(filter-out $(GCC_PLUGINS_CFLAGS) $(SPARC_REG_CFLAGS),$(KBUILD_CFLAGS)) $(CFL) 62 65 63 66 # 64 67 # vDSO code runs in userspace and -pg doesn't help with profiling anyway. ··· 72 73 $(call if_changed,objcopy) 73 74 74 75 CPPFLAGS_vdso32.lds = $(CPPFLAGS_vdso.lds) 75 - VDSO_LDFLAGS_vdso32.lds = -m32 -Wl,-m,elf32_sparc,-soname=linux-gate.so.1 76 + VDSO_LDFLAGS_vdso32.lds = -m elf32_sparc -soname linux-gate.so.1 76 77 77 78 #This makes sure the $(obj) subdirectory exists even though vdso32/ 78 79 #is not a kbuild sub-make subdirectory ··· 90 91 KBUILD_CFLAGS_32 := $(filter-out -mcmodel=medlow,$(KBUILD_CFLAGS_32)) 91 92 KBUILD_CFLAGS_32 := $(filter-out -fno-pic,$(KBUILD_CFLAGS_32)) 92 93 KBUILD_CFLAGS_32 := $(filter-out $(GCC_PLUGINS_CFLAGS),$(KBUILD_CFLAGS_32)) 93 - KBUILD_CFLAGS_32 += -m32 -msoft-float -fpic -mno-app-regs -ffixed-g7 94 + KBUILD_CFLAGS_32 := $(filter-out $(SPARC_REG_CFLAGS),$(KBUILD_CFLAGS_32)) 95 + KBUILD_CFLAGS_32 += -m32 -msoft-float -fpic 94 96 KBUILD_CFLAGS_32 += $(call cc-option, -fno-stack-protector) 95 97 KBUILD_CFLAGS_32 += $(call cc-option, -foptimize-sibling-calls) 96 98 KBUILD_CFLAGS_32 += -fno-omit-frame-pointer ··· 109 109 # The DSO images are built using a special linker script. 110 110 # 111 111 quiet_cmd_vdso = VDSO $@ 112 - cmd_vdso = $(CC) -nostdlib -o $@ \ 112 + cmd_vdso = $(LD) -nostdlib -o $@ \ 113 113 $(VDSO_LDFLAGS) $(VDSO_LDFLAGS_$(filter %.lds,$(^F))) \ 114 - -Wl,-T,$(filter %.lds,$^) $(filter %.o,$^) 114 + -T $(filter %.lds,$^) $(filter %.o,$^) && \ 115 + sh $(srctree)/$(src)/checkundef.sh '$(OBJDUMP)' '$@' 115 116 116 - VDSO_LDFLAGS = -fPIC -shared $(call cc-ldoption, -Wl$(comma)--hash-style=sysv) \ 117 - $(call cc-ldoption, -Wl$(comma)--build-id) -Wl,-Bsymbolic 117 + VDSO_LDFLAGS = -shared $(call ld-option, --hash-style=both) \ 118 + $(call ld-option, --build-id) -Bsymbolic 118 119 GCOV_PROFILE := n 119 120 120 121 #
+10
arch/sparc/vdso/checkundef.sh
··· 1 + #!/bin/sh 2 + objdump="$1" 3 + file="$2" 4 + $objdump -t "$file" | grep '*UUND*' | grep -v '#scratch' > /dev/null 2>&1 5 + if [ $? -eq 1 ]; then 6 + exit 0 7 + else 8 + echo "$file: undefined symbols found" >&2 9 + exit 1 10 + fi
+45 -55
arch/sparc/vdso/vclock_gettime.c
··· 12 12 * Copyright (c) 2017 Oracle and/or its affiliates. All rights reserved. 13 13 */ 14 14 15 - /* Disable profiling for userspace code: */ 16 - #ifndef DISABLE_BRANCH_PROFILING 17 - #define DISABLE_BRANCH_PROFILING 18 - #endif 19 - 20 15 #include <linux/kernel.h> 21 16 #include <linux/time.h> 22 17 #include <linux/string.h> ··· 20 25 #include <asm/timex.h> 21 26 #include <asm/clocksource.h> 22 27 #include <asm/vvar.h> 23 - 24 - #undef TICK_PRIV_BIT 25 - #ifdef CONFIG_SPARC64 26 - #define TICK_PRIV_BIT (1UL << 63) 27 - #else 28 - #define TICK_PRIV_BIT (1ULL << 63) 29 - #endif 30 28 31 29 #ifdef CONFIG_SPARC64 32 30 #define SYSCALL_STRING \ ··· 48 60 * Compute the vvar page's address in the process address space, and return it 49 61 * as a pointer to the vvar_data. 50 62 */ 51 - static notrace noinline struct vvar_data * 52 - get_vvar_data(void) 63 + notrace static __always_inline struct vvar_data *get_vvar_data(void) 53 64 { 54 65 unsigned long ret; 55 66 56 67 /* 57 - * vdso data page is the first vDSO page so grab the return address 68 + * vdso data page is the first vDSO page so grab the PC 58 69 * and move up a page to get to the data page. 59 70 */ 60 - ret = (unsigned long)__builtin_return_address(0); 71 + __asm__("rd %%pc, %0" : "=r" (ret)); 61 72 ret &= ~(8192 - 1); 62 73 ret -= 8192; 63 74 64 75 return (struct vvar_data *) ret; 65 76 } 66 77 67 - static notrace long 68 - vdso_fallback_gettime(long clock, struct timespec *ts) 78 + notrace static long vdso_fallback_gettime(long clock, struct timespec *ts) 69 79 { 70 80 register long num __asm__("g1") = __NR_clock_gettime; 71 81 register long o0 __asm__("o0") = clock; ··· 74 88 return o0; 75 89 } 76 90 77 - static notrace __always_inline long 78 - vdso_fallback_gettimeofday(struct timeval *tv, struct timezone *tz) 91 + notrace static long vdso_fallback_gettimeofday(struct timeval *tv, struct timezone *tz) 79 92 { 80 93 register long num __asm__("g1") = __NR_gettimeofday; 81 94 register long o0 __asm__("o0") = (long) tv; ··· 86 101 } 87 102 88 103 #ifdef CONFIG_SPARC64 89 - static notrace noinline u64 90 - vread_tick(void) { 104 + notrace static __always_inline u64 vread_tick(void) 105 + { 91 106 u64 ret; 92 107 93 - __asm__ __volatile__("rd %%asr24, %0 \n" 94 - ".section .vread_tick_patch, \"ax\" \n" 95 - "rd %%tick, %0 \n" 96 - ".previous \n" 97 - : "=&r" (ret)); 98 - return ret & ~TICK_PRIV_BIT; 108 + __asm__ __volatile__("1:\n\t" 109 + "rd %%tick, %0\n\t" 110 + ".pushsection .tick_patch, \"a\"\n\t" 111 + ".word 1b - ., 1f - .\n\t" 112 + ".popsection\n\t" 113 + ".pushsection .tick_patch_replacement, \"ax\"\n\t" 114 + "1:\n\t" 115 + "rd %%asr24, %0\n\t" 116 + ".popsection\n" 117 + : "=r" (ret)); 118 + return ret; 99 119 } 100 120 #else 101 - static notrace noinline u64 102 - vread_tick(void) 121 + notrace static __always_inline u64 vread_tick(void) 103 122 { 104 - unsigned int lo, hi; 123 + register unsigned long long ret asm("o4"); 105 124 106 - __asm__ __volatile__("rd %%asr24, %%g1\n\t" 107 - "srlx %%g1, 32, %1\n\t" 108 - "srl %%g1, 0, %0\n" 109 - ".section .vread_tick_patch, \"ax\" \n" 110 - "rd %%tick, %%g1\n" 111 - ".previous \n" 112 - : "=&r" (lo), "=&r" (hi) 113 - : 114 - : "g1"); 115 - return lo | ((u64)hi << 32); 125 + __asm__ __volatile__("1:\n\t" 126 + "rd %%tick, %L0\n\t" 127 + "srlx %L0, 32, %H0\n\t" 128 + ".pushsection .tick_patch, \"a\"\n\t" 129 + ".word 1b - ., 1f - .\n\t" 130 + ".popsection\n\t" 131 + ".pushsection .tick_patch_replacement, \"ax\"\n\t" 132 + "1:\n\t" 133 + "rd %%asr24, %L0\n\t" 134 + ".popsection\n" 135 + : "=r" (ret)); 136 + return ret; 116 137 } 117 138 #endif 118 139 119 - static notrace inline u64 120 - vgetsns(struct vvar_data *vvar) 140 + notrace static __always_inline u64 vgetsns(struct vvar_data *vvar) 121 141 { 122 142 u64 v; 123 143 u64 cycles; ··· 132 142 return v * vvar->clock.mult; 133 143 } 134 144 135 - static notrace noinline int 136 - do_realtime(struct vvar_data *vvar, struct timespec *ts) 145 + notrace static __always_inline int do_realtime(struct vvar_data *vvar, 146 + struct timespec *ts) 137 147 { 138 148 unsigned long seq; 139 149 u64 ns; 140 150 141 - ts->tv_nsec = 0; 142 151 do { 143 152 seq = vvar_read_begin(vvar); 144 153 ts->tv_sec = vvar->wall_time_sec; ··· 146 157 ns >>= vvar->clock.shift; 147 158 } while (unlikely(vvar_read_retry(vvar, seq))); 148 159 149 - timespec_add_ns(ts, ns); 160 + ts->tv_sec += __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns); 161 + ts->tv_nsec = ns; 150 162 151 163 return 0; 152 164 } 153 165 154 - static notrace noinline int 155 - do_monotonic(struct vvar_data *vvar, struct timespec *ts) 166 + notrace static __always_inline int do_monotonic(struct vvar_data *vvar, 167 + struct timespec *ts) 156 168 { 157 169 unsigned long seq; 158 170 u64 ns; 159 171 160 - ts->tv_nsec = 0; 161 172 do { 162 173 seq = vvar_read_begin(vvar); 163 174 ts->tv_sec = vvar->monotonic_time_sec; ··· 166 177 ns >>= vvar->clock.shift; 167 178 } while (unlikely(vvar_read_retry(vvar, seq))); 168 179 169 - timespec_add_ns(ts, ns); 180 + ts->tv_sec += __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns); 181 + ts->tv_nsec = ns; 170 182 171 183 return 0; 172 184 } 173 185 174 - static notrace noinline int 175 - do_realtime_coarse(struct vvar_data *vvar, struct timespec *ts) 186 + notrace static int do_realtime_coarse(struct vvar_data *vvar, 187 + struct timespec *ts) 176 188 { 177 189 unsigned long seq; 178 190 ··· 185 195 return 0; 186 196 } 187 197 188 - static notrace noinline int 189 - do_monotonic_coarse(struct vvar_data *vvar, struct timespec *ts) 198 + notrace static int do_monotonic_coarse(struct vvar_data *vvar, 199 + struct timespec *ts) 190 200 { 191 201 unsigned long seq; 192 202
+2 -5
arch/sparc/vdso/vdso-layout.lds.S
··· 73 73 74 74 .text : { *(.text*) } :text =0x90909090, 75 75 76 - .vread_tick_patch : { 77 - vread_tick_patch_start = .; 78 - *(.vread_tick_patch) 79 - vread_tick_patch_end = .; 80 - } 76 + .tick_patch : { *(.tick_patch) } :text 77 + .tick_patch_insns : { *(.tick_patch_insns) } :text 81 78 82 79 /DISCARD/ : { 83 80 *(.discard)
-6
arch/sparc/vdso/vdso2c.c
··· 63 63 sym_vvar_start, 64 64 sym_VDSO_FAKE_SECTION_TABLE_START, 65 65 sym_VDSO_FAKE_SECTION_TABLE_END, 66 - sym_vread_tick, 67 - sym_vread_tick_patch_start, 68 - sym_vread_tick_patch_end 69 66 }; 70 67 71 68 struct vdso_sym { ··· 78 81 [sym_VDSO_FAKE_SECTION_TABLE_END] = { 79 82 "VDSO_FAKE_SECTION_TABLE_END", 0 80 83 }, 81 - [sym_vread_tick] = {"vread_tick", 1}, 82 - [sym_vread_tick_patch_start] = {"vread_tick_patch_start", 1}, 83 - [sym_vread_tick_patch_end] = {"vread_tick_patch_end", 1} 84 84 }; 85 85 86 86 __attribute__((format(printf, 1, 2))) __attribute__((noreturn))
+16 -2
arch/sparc/vdso/vdso2c.h
··· 17 17 unsigned long mapping_size; 18 18 int i; 19 19 unsigned long j; 20 - 21 - ELF(Shdr) *symtab_hdr = NULL, *strtab_hdr; 20 + ELF(Shdr) *symtab_hdr = NULL, *strtab_hdr, *secstrings_hdr, 21 + *patch_sec = NULL; 22 22 ELF(Ehdr) *hdr = (ELF(Ehdr) *)raw_addr; 23 23 ELF(Dyn) *dyn = 0, *dyn_end = 0; 24 + const char *secstrings; 24 25 INT_BITS syms[NSYMS] = {}; 25 26 26 27 ELF(Phdr) *pt = (ELF(Phdr) *)(raw_addr + GET_BE(&hdr->e_phoff)); ··· 64 63 } 65 64 66 65 /* Walk the section table */ 66 + secstrings_hdr = raw_addr + GET_BE(&hdr->e_shoff) + 67 + GET_BE(&hdr->e_shentsize)*GET_BE(&hdr->e_shstrndx); 68 + secstrings = raw_addr + GET_BE(&secstrings_hdr->sh_offset); 67 69 for (i = 0; i < GET_BE(&hdr->e_shnum); i++) { 68 70 ELF(Shdr) *sh = raw_addr + GET_BE(&hdr->e_shoff) + 69 71 GET_BE(&hdr->e_shentsize) * i; 70 72 if (GET_BE(&sh->sh_type) == SHT_SYMTAB) 71 73 symtab_hdr = sh; 74 + 75 + if (!strcmp(secstrings + GET_BE(&sh->sh_name), 76 + ".tick_patch")) 77 + patch_sec = sh; 72 78 } 73 79 74 80 if (!symtab_hdr) ··· 142 134 fprintf(outfile, "const struct vdso_image %s_builtin = {\n", name); 143 135 fprintf(outfile, "\t.data = raw_data,\n"); 144 136 fprintf(outfile, "\t.size = %lu,\n", mapping_size); 137 + if (patch_sec) { 138 + fprintf(outfile, "\t.tick_patch = %lu,\n", 139 + (unsigned long)GET_BE(&patch_sec->sh_offset)); 140 + fprintf(outfile, "\t.tick_patch_len = %lu,\n", 141 + (unsigned long)GET_BE(&patch_sec->sh_size)); 142 + } 145 143 for (i = 0; i < NSYMS; i++) { 146 144 if (required_syms[i].export && syms[i]) 147 145 fprintf(outfile, "\t.sym_%s = %" PRIi64 ",\n",
+23 -16
arch/sparc/vdso/vma.c
··· 16 16 #include <linux/linkage.h> 17 17 #include <linux/random.h> 18 18 #include <linux/elf.h> 19 + #include <asm/cacheflush.h> 20 + #include <asm/spitfire.h> 19 21 #include <asm/vdso.h> 20 22 #include <asm/vvar.h> 21 23 #include <asm/page.h> ··· 42 40 43 41 struct vvar_data *vvar_data; 44 42 45 - #define SAVE_INSTR_SIZE 4 43 + struct tick_patch_entry { 44 + s32 orig, repl; 45 + }; 46 + 47 + static void stick_patch(const struct vdso_image *image) 48 + { 49 + struct tick_patch_entry *p, *p_end; 50 + 51 + p = image->data + image->tick_patch; 52 + p_end = (void *)p + image->tick_patch_len; 53 + while (p < p_end) { 54 + u32 *instr = (void *)&p->orig + p->orig; 55 + u32 *repl = (void *)&p->repl + p->repl; 56 + 57 + *instr = *repl; 58 + flushi(instr); 59 + p++; 60 + } 61 + } 46 62 47 63 /* 48 64 * Allocate pages for the vdso and vvar, and copy in the vdso text from the ··· 88 68 if (!cpp) 89 69 goto oom; 90 70 91 - if (vdso_fix_stick) { 92 - /* 93 - * If the system uses %tick instead of %stick, patch the VDSO 94 - * with instruction reading %tick instead of %stick. 95 - */ 96 - unsigned int j, k = SAVE_INSTR_SIZE; 97 - unsigned char *data = image->data; 98 - 99 - for (j = image->sym_vread_tick_patch_start; 100 - j < image->sym_vread_tick_patch_end; j++) { 101 - 102 - data[image->sym_vread_tick + k] = data[j]; 103 - k++; 104 - } 105 - } 71 + if (tlb_type != spitfire) 72 + stick_patch(image); 106 73 107 74 for (i = 0; i < cnpages; i++) { 108 75 cp = alloc_page(GFP_KERNEL);