diff options
Diffstat (limited to 'arch/tile/kernel')
-rw-r--r-- | arch/tile/kernel/smp.c | 1 | ||||
-rw-r--r-- | arch/tile/kernel/time.c | 61 | ||||
-rw-r--r-- | arch/tile/kernel/traps.c | 2 | ||||
-rw-r--r-- | arch/tile/kernel/vdso/vdso.lds.S | 2 | ||||
-rw-r--r-- | arch/tile/kernel/vdso/vgettimeofday.c | 176 | ||||
-rw-r--r-- | arch/tile/kernel/vmlinux.lds.S | 2 |
6 files changed, 177 insertions, 67 deletions
diff --git a/arch/tile/kernel/smp.c b/arch/tile/kernel/smp.c index 01e8ab29f43a..19eaa62d456a 100644 --- a/arch/tile/kernel/smp.c +++ b/arch/tile/kernel/smp.c | |||
@@ -183,6 +183,7 @@ void flush_icache_range(unsigned long start, unsigned long end) | |||
183 | preempt_enable(); | 183 | preempt_enable(); |
184 | } | 184 | } |
185 | } | 185 | } |
186 | EXPORT_SYMBOL(flush_icache_range); | ||
186 | 187 | ||
187 | 188 | ||
188 | /* Called when smp_send_reschedule() triggers IRQ_RESCHEDULE. */ | 189 | /* Called when smp_send_reschedule() triggers IRQ_RESCHEDULE. */ |
diff --git a/arch/tile/kernel/time.c b/arch/tile/kernel/time.c index d8fbc289e680..c1b362277fb7 100644 --- a/arch/tile/kernel/time.c +++ b/arch/tile/kernel/time.c | |||
@@ -249,33 +249,52 @@ cycles_t ns2cycles(unsigned long nsecs) | |||
249 | 249 | ||
250 | void update_vsyscall_tz(void) | 250 | void update_vsyscall_tz(void) |
251 | { | 251 | { |
252 | /* Userspace gettimeofday will spin while this value is odd. */ | 252 | write_seqcount_begin(&vdso_data->tz_seq); |
253 | ++vdso_data->tz_update_count; | ||
254 | smp_wmb(); | ||
255 | vdso_data->tz_minuteswest = sys_tz.tz_minuteswest; | 253 | vdso_data->tz_minuteswest = sys_tz.tz_minuteswest; |
256 | vdso_data->tz_dsttime = sys_tz.tz_dsttime; | 254 | vdso_data->tz_dsttime = sys_tz.tz_dsttime; |
257 | smp_wmb(); | 255 | write_seqcount_end(&vdso_data->tz_seq); |
258 | ++vdso_data->tz_update_count; | ||
259 | } | 256 | } |
260 | 257 | ||
261 | void update_vsyscall(struct timekeeper *tk) | 258 | void update_vsyscall(struct timekeeper *tk) |
262 | { | 259 | { |
263 | struct timespec *wtm = &tk->wall_to_monotonic; | 260 | if (tk->tkr.clock != &cycle_counter_cs) |
264 | struct clocksource *clock = tk->tkr.clock; | ||
265 | |||
266 | if (clock != &cycle_counter_cs) | ||
267 | return; | 261 | return; |
268 | 262 | ||
269 | /* Userspace gettimeofday will spin while this value is odd. */ | 263 | write_seqcount_begin(&vdso_data->tb_seq); |
270 | ++vdso_data->tb_update_count; | 264 | |
271 | smp_wmb(); | 265 | vdso_data->cycle_last = tk->tkr.cycle_last; |
272 | vdso_data->xtime_tod_stamp = tk->tkr.cycle_last; | 266 | vdso_data->mask = tk->tkr.mask; |
273 | vdso_data->xtime_clock_sec = tk->xtime_sec; | 267 | vdso_data->mult = tk->tkr.mult; |
274 | vdso_data->xtime_clock_nsec = tk->tkr.xtime_nsec; | 268 | vdso_data->shift = tk->tkr.shift; |
275 | vdso_data->wtom_clock_sec = wtm->tv_sec; | 269 | |
276 | vdso_data->wtom_clock_nsec = wtm->tv_nsec; | 270 | vdso_data->wall_time_sec = tk->xtime_sec; |
277 | vdso_data->mult = tk->tkr.mult; | 271 | vdso_data->wall_time_snsec = tk->tkr.xtime_nsec; |
278 | vdso_data->shift = tk->tkr.shift; | 272 | |
279 | smp_wmb(); | 273 | vdso_data->monotonic_time_sec = tk->xtime_sec |
280 | ++vdso_data->tb_update_count; | 274 | + tk->wall_to_monotonic.tv_sec; |
275 | vdso_data->monotonic_time_snsec = tk->tkr.xtime_nsec | ||
276 | + ((u64)tk->wall_to_monotonic.tv_nsec | ||
277 | << tk->tkr.shift); | ||
278 | while (vdso_data->monotonic_time_snsec >= | ||
279 | (((u64)NSEC_PER_SEC) << tk->tkr.shift)) { | ||
280 | vdso_data->monotonic_time_snsec -= | ||
281 | ((u64)NSEC_PER_SEC) << tk->tkr.shift; | ||
282 | vdso_data->monotonic_time_sec++; | ||
283 | } | ||
284 | |||
285 | vdso_data->wall_time_coarse_sec = tk->xtime_sec; | ||
286 | vdso_data->wall_time_coarse_nsec = (long)(tk->tkr.xtime_nsec >> | ||
287 | tk->tkr.shift); | ||
288 | |||
289 | vdso_data->monotonic_time_coarse_sec = | ||
290 | vdso_data->wall_time_coarse_sec + tk->wall_to_monotonic.tv_sec; | ||
291 | vdso_data->monotonic_time_coarse_nsec = | ||
292 | vdso_data->wall_time_coarse_nsec + tk->wall_to_monotonic.tv_nsec; | ||
293 | |||
294 | while (vdso_data->monotonic_time_coarse_nsec >= NSEC_PER_SEC) { | ||
295 | vdso_data->monotonic_time_coarse_nsec -= NSEC_PER_SEC; | ||
296 | vdso_data->monotonic_time_coarse_sec++; | ||
297 | } | ||
298 | |||
299 | write_seqcount_end(&vdso_data->tb_seq); | ||
281 | } | 300 | } |
diff --git a/arch/tile/kernel/traps.c b/arch/tile/kernel/traps.c index f3ceb6308e42..86900ccd4977 100644 --- a/arch/tile/kernel/traps.c +++ b/arch/tile/kernel/traps.c | |||
@@ -277,7 +277,7 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num, | |||
277 | if (fixup_exception(regs)) /* ILL_TRANS or UNALIGN_DATA */ | 277 | if (fixup_exception(regs)) /* ILL_TRANS or UNALIGN_DATA */ |
278 | return; | 278 | return; |
279 | if (fault_num >= 0 && | 279 | if (fault_num >= 0 && |
280 | fault_num < sizeof(int_name)/sizeof(int_name[0]) && | 280 | fault_num < ARRAY_SIZE(int_name) && |
281 | int_name[fault_num] != NULL) | 281 | int_name[fault_num] != NULL) |
282 | name = int_name[fault_num]; | 282 | name = int_name[fault_num]; |
283 | else | 283 | else |
diff --git a/arch/tile/kernel/vdso/vdso.lds.S b/arch/tile/kernel/vdso/vdso.lds.S index 041cd6c39c83..731529f3f06f 100644 --- a/arch/tile/kernel/vdso/vdso.lds.S +++ b/arch/tile/kernel/vdso/vdso.lds.S | |||
@@ -82,6 +82,8 @@ VERSION | |||
82 | __vdso_rt_sigreturn; | 82 | __vdso_rt_sigreturn; |
83 | __vdso_gettimeofday; | 83 | __vdso_gettimeofday; |
84 | gettimeofday; | 84 | gettimeofday; |
85 | __vdso_clock_gettime; | ||
86 | clock_gettime; | ||
85 | local:*; | 87 | local:*; |
86 | }; | 88 | }; |
87 | } | 89 | } |
diff --git a/arch/tile/kernel/vdso/vgettimeofday.c b/arch/tile/kernel/vdso/vgettimeofday.c index e933fb9fbf5c..8bb21eda07d8 100644 --- a/arch/tile/kernel/vdso/vgettimeofday.c +++ b/arch/tile/kernel/vdso/vgettimeofday.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #define VDSO_BUILD /* avoid some shift warnings for -m32 in <asm/page.h> */ | 15 | #define VDSO_BUILD /* avoid some shift warnings for -m32 in <asm/page.h> */ |
16 | #include <linux/time.h> | 16 | #include <linux/time.h> |
17 | #include <asm/timex.h> | 17 | #include <asm/timex.h> |
18 | #include <asm/unistd.h> | ||
18 | #include <asm/vdso.h> | 19 | #include <asm/vdso.h> |
19 | 20 | ||
20 | #if CHIP_HAS_SPLIT_CYCLE() | 21 | #if CHIP_HAS_SPLIT_CYCLE() |
@@ -35,6 +36,11 @@ static inline cycles_t get_cycles_inline(void) | |||
35 | #define get_cycles get_cycles_inline | 36 | #define get_cycles get_cycles_inline |
36 | #endif | 37 | #endif |
37 | 38 | ||
39 | struct syscall_return_value { | ||
40 | long value; | ||
41 | long error; | ||
42 | }; | ||
43 | |||
38 | /* | 44 | /* |
39 | * Find out the vDSO data page address in the process address space. | 45 | * Find out the vDSO data page address in the process address space. |
40 | */ | 46 | */ |
@@ -50,59 +56,143 @@ inline unsigned long get_datapage(void) | |||
50 | return ret; | 56 | return ret; |
51 | } | 57 | } |
52 | 58 | ||
53 | int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz) | 59 | static inline u64 vgetsns(struct vdso_data *vdso) |
60 | { | ||
61 | return ((get_cycles() - vdso->cycle_last) & vdso->mask) * vdso->mult; | ||
62 | } | ||
63 | |||
64 | static inline int do_realtime(struct vdso_data *vdso, struct timespec *ts) | ||
65 | { | ||
66 | unsigned count; | ||
67 | u64 ns; | ||
68 | |||
69 | do { | ||
70 | count = read_seqcount_begin(&vdso->tb_seq); | ||
71 | ts->tv_sec = vdso->wall_time_sec; | ||
72 | ns = vdso->wall_time_snsec; | ||
73 | ns += vgetsns(vdso); | ||
74 | ns >>= vdso->shift; | ||
75 | } while (unlikely(read_seqcount_retry(&vdso->tb_seq, count))); | ||
76 | |||
77 | ts->tv_sec += __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns); | ||
78 | ts->tv_nsec = ns; | ||
79 | |||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | static inline int do_monotonic(struct vdso_data *vdso, struct timespec *ts) | ||
84 | { | ||
85 | unsigned count; | ||
86 | u64 ns; | ||
87 | |||
88 | do { | ||
89 | count = read_seqcount_begin(&vdso->tb_seq); | ||
90 | ts->tv_sec = vdso->monotonic_time_sec; | ||
91 | ns = vdso->monotonic_time_snsec; | ||
92 | ns += vgetsns(vdso); | ||
93 | ns >>= vdso->shift; | ||
94 | } while (unlikely(read_seqcount_retry(&vdso->tb_seq, count))); | ||
95 | |||
96 | ts->tv_sec += __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns); | ||
97 | ts->tv_nsec = ns; | ||
98 | |||
99 | return 0; | ||
100 | } | ||
101 | |||
102 | static inline int do_realtime_coarse(struct vdso_data *vdso, | ||
103 | struct timespec *ts) | ||
104 | { | ||
105 | unsigned count; | ||
106 | |||
107 | do { | ||
108 | count = read_seqcount_begin(&vdso->tb_seq); | ||
109 | ts->tv_sec = vdso->wall_time_coarse_sec; | ||
110 | ts->tv_nsec = vdso->wall_time_coarse_nsec; | ||
111 | } while (unlikely(read_seqcount_retry(&vdso->tb_seq, count))); | ||
112 | |||
113 | return 0; | ||
114 | } | ||
115 | |||
116 | static inline int do_monotonic_coarse(struct vdso_data *vdso, | ||
117 | struct timespec *ts) | ||
54 | { | 118 | { |
55 | cycles_t cycles; | 119 | unsigned count; |
56 | unsigned long count, sec, ns; | 120 | |
57 | volatile struct vdso_data *vdso_data; | 121 | do { |
122 | count = read_seqcount_begin(&vdso->tb_seq); | ||
123 | ts->tv_sec = vdso->monotonic_time_coarse_sec; | ||
124 | ts->tv_nsec = vdso->monotonic_time_coarse_nsec; | ||
125 | } while (unlikely(read_seqcount_retry(&vdso->tb_seq, count))); | ||
126 | |||
127 | return 0; | ||
128 | } | ||
129 | |||
130 | struct syscall_return_value __vdso_gettimeofday(struct timeval *tv, | ||
131 | struct timezone *tz) | ||
132 | { | ||
133 | struct syscall_return_value ret = { 0, 0 }; | ||
134 | unsigned count; | ||
135 | struct vdso_data *vdso = (struct vdso_data *)get_datapage(); | ||
58 | 136 | ||
59 | vdso_data = (struct vdso_data *)get_datapage(); | ||
60 | /* The use of the timezone is obsolete, normally tz is NULL. */ | 137 | /* The use of the timezone is obsolete, normally tz is NULL. */ |
61 | if (unlikely(tz != NULL)) { | 138 | if (unlikely(tz != NULL)) { |
62 | while (1) { | 139 | do { |
63 | /* Spin until the update finish. */ | 140 | count = read_seqcount_begin(&vdso->tz_seq); |
64 | count = vdso_data->tz_update_count; | 141 | tz->tz_minuteswest = vdso->tz_minuteswest; |
65 | if (count & 1) | 142 | tz->tz_dsttime = vdso->tz_dsttime; |
66 | continue; | 143 | } while (unlikely(read_seqcount_retry(&vdso->tz_seq, count))); |
67 | |||
68 | tz->tz_minuteswest = vdso_data->tz_minuteswest; | ||
69 | tz->tz_dsttime = vdso_data->tz_dsttime; | ||
70 | |||
71 | /* Check whether updated, read again if so. */ | ||
72 | if (count == vdso_data->tz_update_count) | ||
73 | break; | ||
74 | } | ||
75 | } | 144 | } |
76 | 145 | ||
77 | if (unlikely(tv == NULL)) | 146 | if (unlikely(tv == NULL)) |
78 | return 0; | 147 | return ret; |
79 | |||
80 | while (1) { | ||
81 | /* Spin until the update finish. */ | ||
82 | count = vdso_data->tb_update_count; | ||
83 | if (count & 1) | ||
84 | continue; | ||
85 | |||
86 | sec = vdso_data->xtime_clock_sec; | ||
87 | cycles = get_cycles() - vdso_data->xtime_tod_stamp; | ||
88 | ns = (cycles * vdso_data->mult) + vdso_data->xtime_clock_nsec; | ||
89 | ns >>= vdso_data->shift; | ||
90 | |||
91 | if (ns >= NSEC_PER_SEC) { | ||
92 | ns -= NSEC_PER_SEC; | ||
93 | sec += 1; | ||
94 | } | ||
95 | |||
96 | /* Check whether updated, read again if so. */ | ||
97 | if (count == vdso_data->tb_update_count) | ||
98 | break; | ||
99 | } | ||
100 | 148 | ||
101 | tv->tv_sec = sec; | 149 | do_realtime(vdso, (struct timespec *)tv); |
102 | tv->tv_usec = ns / 1000; | 150 | tv->tv_usec /= 1000; |
103 | 151 | ||
104 | return 0; | 152 | return ret; |
105 | } | 153 | } |
106 | 154 | ||
107 | int gettimeofday(struct timeval *tv, struct timezone *tz) | 155 | int gettimeofday(struct timeval *tv, struct timezone *tz) |
108 | __attribute__((weak, alias("__vdso_gettimeofday"))); | 156 | __attribute__((weak, alias("__vdso_gettimeofday"))); |
157 | |||
158 | static struct syscall_return_value vdso_fallback_gettime(long clock, | ||
159 | struct timespec *ts) | ||
160 | { | ||
161 | struct syscall_return_value ret; | ||
162 | __asm__ __volatile__ ( | ||
163 | "swint1" | ||
164 | : "=R00" (ret.value), "=R01" (ret.error) | ||
165 | : "R10" (__NR_clock_gettime), "R00" (clock), "R01" (ts) | ||
166 | : "r2", "r3", "r4", "r5", "r6", "r7", | ||
167 | "r8", "r9", "r11", "r12", "r13", "r14", "r15", | ||
168 | "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", | ||
169 | "r24", "r25", "r26", "r27", "r28", "r29", "memory"); | ||
170 | return ret; | ||
171 | } | ||
172 | |||
173 | struct syscall_return_value __vdso_clock_gettime(clockid_t clock, | ||
174 | struct timespec *ts) | ||
175 | { | ||
176 | struct vdso_data *vdso = (struct vdso_data *)get_datapage(); | ||
177 | struct syscall_return_value ret = { 0, 0 }; | ||
178 | |||
179 | switch (clock) { | ||
180 | case CLOCK_REALTIME: | ||
181 | do_realtime(vdso, ts); | ||
182 | return ret; | ||
183 | case CLOCK_MONOTONIC: | ||
184 | do_monotonic(vdso, ts); | ||
185 | return ret; | ||
186 | case CLOCK_REALTIME_COARSE: | ||
187 | do_realtime_coarse(vdso, ts); | ||
188 | return ret; | ||
189 | case CLOCK_MONOTONIC_COARSE: | ||
190 | do_monotonic_coarse(vdso, ts); | ||
191 | return ret; | ||
192 | default: | ||
193 | return vdso_fallback_gettime(clock, ts); | ||
194 | } | ||
195 | } | ||
196 | |||
197 | int clock_gettime(clockid_t clock, struct timespec *ts) | ||
198 | __attribute__((weak, alias("__vdso_clock_gettime"))); | ||
diff --git a/arch/tile/kernel/vmlinux.lds.S b/arch/tile/kernel/vmlinux.lds.S index f1819423ffc9..0e059a0101ea 100644 --- a/arch/tile/kernel/vmlinux.lds.S +++ b/arch/tile/kernel/vmlinux.lds.S | |||
@@ -66,11 +66,9 @@ SECTIONS | |||
66 | 66 | ||
67 | . = ALIGN(PAGE_SIZE); | 67 | . = ALIGN(PAGE_SIZE); |
68 | __init_begin = .; | 68 | __init_begin = .; |
69 | VMLINUX_SYMBOL(_sinitdata) = .; | ||
70 | INIT_DATA_SECTION(16) :data =0 | 69 | INIT_DATA_SECTION(16) :data =0 |
71 | PERCPU_SECTION(L2_CACHE_BYTES) | 70 | PERCPU_SECTION(L2_CACHE_BYTES) |
72 | . = ALIGN(PAGE_SIZE); | 71 | . = ALIGN(PAGE_SIZE); |
73 | VMLINUX_SYMBOL(_einitdata) = .; | ||
74 | __init_end = .; | 72 | __init_end = .; |
75 | 73 | ||
76 | _sdata = .; /* Start of data section */ | 74 | _sdata = .; /* Start of data section */ |