Skip to content

Commit 8c071b0

Browse files
author
Martin Schwidefsky
committed
s390/time: correct use of store clock fast
The result of the store-clock-fast (STCKF) instruction is a bit fuzzy. It can happen that the value stored on one CPU is smaller than the value stored on another CPU, although the order of the stores is the other way around. This can cause deltas of get_tod_clock() values to become negative when they should not be. We need to be more careful with store-clock-fast, this patch partially reverts git commit e4b7b4238e666682555461fa52eecd74652f36bb "time: always use stckf instead of stck if available". The get_tod_clock() function now uses the store-clock-extended (STCKE) instruction. get_tod_clock_fast() can be used if the fuzziness of store-clock-fast is acceptable e.g. for wait loops local to a CPU. Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
1 parent 9784bd4 commit 8c071b0

File tree

7 files changed

+34
-34
lines changed

7 files changed

+34
-34
lines changed

arch/s390/include/asm/timex.h

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -71,30 +71,30 @@ static inline void local_tick_enable(unsigned long long comp)
7171

7272
typedef unsigned long long cycles_t;
7373

74-
static inline unsigned long long get_tod_clock(void)
75-
{
76-
unsigned long long clk;
77-
78-
#ifdef CONFIG_HAVE_MARCH_Z9_109_FEATURES
79-
asm volatile(".insn s,0xb27c0000,%0" : "=Q" (clk) : : "cc");
80-
#else
81-
asm volatile("stck %0" : "=Q" (clk) : : "cc");
82-
#endif
83-
return clk;
84-
}
85-
8674
static inline void get_tod_clock_ext(char *clk)
8775
{
8876
asm volatile("stcke %0" : "=Q" (*clk) : : "cc");
8977
}
9078

91-
static inline unsigned long long get_tod_clock_xt(void)
79+
static inline unsigned long long get_tod_clock(void)
9280
{
9381
unsigned char clk[16];
9482
get_tod_clock_ext(clk);
9583
return *((unsigned long long *)&clk[1]);
9684
}
9785

86+
static inline unsigned long long get_tod_clock_fast(void)
87+
{
88+
#ifdef CONFIG_HAVE_MARCH_Z9_109_FEATURES
89+
unsigned long long clk;
90+
91+
asm volatile("stckf %0" : "=Q" (clk) : : "cc");
92+
return clk;
93+
#else
94+
return get_tod_clock();
95+
#endif
96+
}
97+
9898
static inline cycles_t get_cycles(void)
9999
{
100100
return (cycles_t) get_tod_clock() >> 2;
@@ -125,7 +125,7 @@ extern u64 sched_clock_base_cc;
125125
*/
126126
static inline unsigned long long get_tod_clock_monotonic(void)
127127
{
128-
return get_tod_clock_xt() - sched_clock_base_cc;
128+
return get_tod_clock() - sched_clock_base_cc;
129129
}
130130

131131
/**

arch/s390/kernel/debug.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -867,7 +867,7 @@ static inline void
867867
debug_finish_entry(debug_info_t * id, debug_entry_t* active, int level,
868868
int exception)
869869
{
870-
active->id.stck = get_tod_clock();
870+
active->id.stck = get_tod_clock_fast();
871871
active->id.fields.cpuid = smp_processor_id();
872872
active->caller = __builtin_return_address(0);
873873
active->id.fields.exception = exception;

arch/s390/kvm/interrupt.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,7 @@ static int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu)
385385
}
386386

387387
if ((!rc) && (vcpu->arch.sie_block->ckc <
388-
get_tod_clock() + vcpu->arch.sie_block->epoch)) {
388+
get_tod_clock_fast() + vcpu->arch.sie_block->epoch)) {
389389
if ((!psw_extint_disabled(vcpu)) &&
390390
(vcpu->arch.sie_block->gcr[0] & 0x800ul))
391391
rc = 1;
@@ -425,7 +425,7 @@ int kvm_s390_handle_wait(struct kvm_vcpu *vcpu)
425425
goto no_timer;
426426
}
427427

428-
now = get_tod_clock() + vcpu->arch.sie_block->epoch;
428+
now = get_tod_clock_fast() + vcpu->arch.sie_block->epoch;
429429
if (vcpu->arch.sie_block->ckc < now) {
430430
__unset_cpu_idle(vcpu);
431431
return 0;
@@ -515,7 +515,7 @@ void kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu)
515515
}
516516

517517
if ((vcpu->arch.sie_block->ckc <
518-
get_tod_clock() + vcpu->arch.sie_block->epoch))
518+
get_tod_clock_fast() + vcpu->arch.sie_block->epoch))
519519
__try_deliver_ckc_interrupt(vcpu);
520520

521521
if (atomic_read(&fi->active)) {

arch/s390/lib/delay.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ static void __udelay_disabled(unsigned long long usecs)
4444
do {
4545
set_clock_comparator(end);
4646
vtime_stop_cpu();
47-
} while (get_tod_clock() < end);
47+
} while (get_tod_clock_fast() < end);
4848
lockdep_on();
4949
__ctl_load(cr0, 0, 0);
5050
__ctl_load(cr6, 6, 6);
@@ -55,7 +55,7 @@ static void __udelay_enabled(unsigned long long usecs)
5555
{
5656
u64 clock_saved, end;
5757

58-
end = get_tod_clock() + (usecs << 12);
58+
end = get_tod_clock_fast() + (usecs << 12);
5959
do {
6060
clock_saved = 0;
6161
if (end < S390_lowcore.clock_comparator) {
@@ -65,7 +65,7 @@ static void __udelay_enabled(unsigned long long usecs)
6565
vtime_stop_cpu();
6666
if (clock_saved)
6767
local_tick_enable(clock_saved);
68-
} while (get_tod_clock() < end);
68+
} while (get_tod_clock_fast() < end);
6969
}
7070

7171
/*
@@ -109,8 +109,8 @@ void udelay_simple(unsigned long long usecs)
109109
{
110110
u64 end;
111111

112-
end = get_tod_clock() + (usecs << 12);
113-
while (get_tod_clock() < end)
112+
end = get_tod_clock_fast() + (usecs << 12);
113+
while (get_tod_clock_fast() < end)
114114
cpu_relax();
115115
}
116116

@@ -120,10 +120,10 @@ void __ndelay(unsigned long long nsecs)
120120

121121
nsecs <<= 9;
122122
do_div(nsecs, 125);
123-
end = get_tod_clock() + nsecs;
123+
end = get_tod_clock_fast() + nsecs;
124124
if (nsecs & ~0xfffUL)
125125
__udelay(nsecs >> 12);
126-
while (get_tod_clock() < end)
126+
while (get_tod_clock_fast() < end)
127127
barrier();
128128
}
129129
EXPORT_SYMBOL(__ndelay);

drivers/s390/char/sclp.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -486,7 +486,7 @@ sclp_sync_wait(void)
486486
timeout = 0;
487487
if (timer_pending(&sclp_request_timer)) {
488488
/* Get timeout TOD value */
489-
timeout = get_tod_clock() +
489+
timeout = get_tod_clock_fast() +
490490
sclp_tod_from_jiffies(sclp_request_timer.expires -
491491
jiffies);
492492
}
@@ -508,7 +508,7 @@ sclp_sync_wait(void)
508508
while (sclp_running_state != sclp_running_state_idle) {
509509
/* Check for expired request timer */
510510
if (timer_pending(&sclp_request_timer) &&
511-
get_tod_clock() > timeout &&
511+
get_tod_clock_fast() > timeout &&
512512
del_timer(&sclp_request_timer))
513513
sclp_request_timer.function(sclp_request_timer.data);
514514
cpu_relax();

drivers/s390/cio/cio.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -878,9 +878,9 @@ static void css_reset(void)
878878
atomic_inc(&chpid_reset_count);
879879
}
880880
/* Wait for machine check for all channel paths. */
881-
timeout = get_tod_clock() + (RCHP_TIMEOUT << 12);
881+
timeout = get_tod_clock_fast() + (RCHP_TIMEOUT << 12);
882882
while (atomic_read(&chpid_reset_count) != 0) {
883-
if (get_tod_clock() > timeout)
883+
if (get_tod_clock_fast() > timeout)
884884
break;
885885
cpu_relax();
886886
}

drivers/s390/cio/qdio_main.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -338,10 +338,10 @@ static int qdio_siga_output(struct qdio_q *q, unsigned int *busy_bit,
338338
retries++;
339339

340340
if (!start_time) {
341-
start_time = get_tod_clock();
341+
start_time = get_tod_clock_fast();
342342
goto again;
343343
}
344-
if ((get_tod_clock() - start_time) < QDIO_BUSY_BIT_PATIENCE)
344+
if (get_tod_clock_fast() - start_time < QDIO_BUSY_BIT_PATIENCE)
345345
goto again;
346346
}
347347
if (retries) {
@@ -504,7 +504,7 @@ static int get_inbound_buffer_frontier(struct qdio_q *q)
504504
int count, stop;
505505
unsigned char state = 0;
506506

507-
q->timestamp = get_tod_clock();
507+
q->timestamp = get_tod_clock_fast();
508508

509509
/*
510510
* Don't check 128 buffers, as otherwise qdio_inbound_q_moved
@@ -595,7 +595,7 @@ static inline int qdio_inbound_q_done(struct qdio_q *q)
595595
* At this point we know, that inbound first_to_check
596596
* has (probably) not moved (see qdio_inbound_processing).
597597
*/
598-
if (get_tod_clock() > q->u.in.timestamp + QDIO_INPUT_THRESHOLD) {
598+
if (get_tod_clock_fast() > q->u.in.timestamp + QDIO_INPUT_THRESHOLD) {
599599
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in done:%02x",
600600
q->first_to_check);
601601
return 1;
@@ -728,7 +728,7 @@ static int get_outbound_buffer_frontier(struct qdio_q *q)
728728
int count, stop;
729729
unsigned char state = 0;
730730

731-
q->timestamp = get_tod_clock();
731+
q->timestamp = get_tod_clock_fast();
732732

733733
if (need_siga_sync(q))
734734
if (((queue_type(q) != QDIO_IQDIO_QFMT) &&

0 commit comments

Comments
 (0)