[kvm-unit-tests,v4,12/13] s390x: Add time functions to lib
diff mbox series

Message ID 20190103100806.9039-13-frankja@linux.ibm.com
State New
Headers show
Series
  • 390x: Add cross hypervisor and disk boot
Related show

Commit Message

Janosch Frank Jan. 3, 2019, 10:08 a.m. UTC
Always good to know what time it is.

Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
---
 lib/s390x/time.c |  18 ++++++++++
 lib/s390x/time.h | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 s390x/Makefile   |   1 +
 3 files changed, 127 insertions(+)
 create mode 100644 lib/s390x/time.c
 create mode 100644 lib/s390x/time.h

Comments

Thomas Huth Jan. 3, 2019, 1:52 p.m. UTC | #1
On 2019-01-03 11:08, Janosch Frank wrote:
> Always good to know what time it is.
> 
> Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
> ---
>  lib/s390x/time.c |  18 ++++++++++
>  lib/s390x/time.h | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  s390x/Makefile   |   1 +
>  3 files changed, 127 insertions(+)
>  create mode 100644 lib/s390x/time.c
>  create mode 100644 lib/s390x/time.h
[...]
> +/*
> + * STCKE returns 16 bytes, which include the epoch, tod value and a
> + * programmable field. The value has to be trimmed to be able to work
> + * with it. As there's still some time to 2042, this code is not ready
> + * for multi epoch values.
> + */
> +static inline void stcke(char *tod)
> +{
> +	asm volatile(
> +		"	stcke	%[tod]\n"
> +		: [tod] "=Q" (tod)
> +		: : "cc");
> +}

I'm not an inline-assembly wizzard, but the "=Q" constraint looks wrong
to me here. Are you sure that this is working as expected?
Maybe you could simply scratch that stcke() function if you don't need it?

 Thomas
Heiko Carstens Jan. 4, 2019, 8:42 a.m. UTC | #2
On Thu, Jan 03, 2019 at 02:52:15PM +0100, Thomas Huth wrote:
> On 2019-01-03 11:08, Janosch Frank wrote:
> > +/*
> > + * STCKE returns 16 bytes, which include the epoch, tod value and a
> > + * programmable field. The value has to be trimmed to be able to work
> > + * with it. As there's still some time to 2042, this code is not ready
> > + * for multi epoch values.
> > + */
> > +static inline void stcke(char *tod)
> > +{
> > +	asm volatile(
> > +		"	stcke	%[tod]\n"
> > +		: [tod] "=Q" (tod)
> > +		: : "cc");
> > +}
> 
> I'm not an inline-assembly wizzard, but the "=Q" constraint looks wrong
> to me here. Are you sure that this is working as expected?

Yes, this is wrong. That's the reason why the kernel variant has the
typedef + cast (see get_tod_clock_ext() in arch/s390/include/asm/timex.h).

The variant above tells the compiler that only a single byte is written to.
Janosch Frank Jan. 4, 2019, 10:06 a.m. UTC | #3
On 04.01.19 09:42, Heiko Carstens wrote:
> On Thu, Jan 03, 2019 at 02:52:15PM +0100, Thomas Huth wrote:
>> On 2019-01-03 11:08, Janosch Frank wrote:
>>> +/*
>>> + * STCKE returns 16 bytes, which include the epoch, tod value and a
>>> + * programmable field. The value has to be trimmed to be able to work
>>> + * with it. As there's still some time to 2042, this code is not ready
>>> + * for multi epoch values.
>>> + */
>>> +static inline void stcke(char *tod)
>>> +{
>>> +	asm volatile(
>>> +		"	stcke	%[tod]\n"
>>> +		: [tod] "=Q" (tod)
>>> +		: : "cc");
>>> +}
>>
>> I'm not an inline-assembly wizzard, but the "=Q" constraint looks wrong
>> to me here. Are you sure that this is working as expected?
> 
> Yes, this is wrong. That's the reason why the kernel variant has the
> typedef + cast (see get_tod_clock_ext() in arch/s390/include/asm/timex.h).
> 
> The variant above tells the compiler that only a single byte is written to.
> 

Yep, was removed yesterday already.
If tests for multi epoch enablement come up they'll have to introduce it
again.

For now I'll keep #12 and #13 on hold until they are needed upstream, I
think there will not be huge conflicts in that area if the need to
upstream it arises later.

Patch
diff mbox series

diff --git a/lib/s390x/time.c b/lib/s390x/time.c
new file mode 100644
index 0000000..e0fbcfc
--- /dev/null
+++ b/lib/s390x/time.c
@@ -0,0 +1,18 @@ 
+#include <libcflat.h>
+#include "time.h"
+
+uint64_t time_get_ns(void)
+{
+	unsigned long long tod;
+
+	tod = stckf();
+	return tod_to_ns(tod);
+}
+
+uint64_t time_get_s(void)
+{
+	uint64_t ns;
+
+	ns = time_get_ns();
+	return ns / 1000000UL;
+}
diff --git a/lib/s390x/time.h b/lib/s390x/time.h
new file mode 100644
index 0000000..96bb974
--- /dev/null
+++ b/lib/s390x/time.h
@@ -0,0 +1,108 @@ 
+/*
+ * Time related definitions.
+ *
+ * Mostly copied from arch/s390/include/asm/timex.h from the Linux
+ * kernel git.
+ *
+ * Copyright IBM Corp. 1999
+ *
+ * Derived from "include/asm-i386/timex.h"
+ * Copyright (C) 1992, Linus Torvalds
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.
+ */
+#ifndef TIME_H
+#define TIME_H
+
+/* The value of the TOD clock for 1.1.1970. */
+#define TOD_UNIX_EPOCH 0x7d91048bca000000ULL
+
+static inline void set_clock_comparator(uint64_t time)
+{
+	asm volatile("sckc %0" : : "Q" (time));
+}
+
+static inline void store_clock_comparator(uint64_t *time)
+{
+	asm volatile("stckc %0" : "=Q" (*time));
+}
+
+static inline int set_tod_clock(uint64_t time)
+{
+	int cc;
+
+	asm volatile(
+		"   sck   %1\n"
+		"   ipm   %0\n"
+		"   srl   %0,28\n"
+		: "=d" (cc) : "Q" (time) : "cc");
+	return cc;
+}
+
+static inline uint64_t stck(void)
+{
+	uint64_t tod;
+
+	asm volatile(
+		"	stck	%[tod]\n"
+		: [tod] "=Q" (tod) : : "cc"
+		);
+	return tod;
+}
+
+static inline uint64_t stckf(void)
+{
+	uint64_t tod;
+
+	asm volatile(
+		"	.machine push\n"
+		"	.machine \"z9-109\"\n"
+		"	stckf	%[tod]\n"
+		"	.machine pop\n"
+		: [tod] "=Q" (tod)
+		: : "cc");
+	return tod;
+}
+
+/*
+ * STCKE returns 16 bytes, which include the epoch, tod value and a
+ * programmable field. The value has to be trimmed to be able to work
+ * with it. As there's still some time to 2042, this code is not ready
+ * for multi epoch values.
+ */
+static inline void stcke(char *tod)
+{
+	asm volatile(
+		"	stcke	%[tod]\n"
+		: [tod] "=Q" (tod)
+		: : "cc");
+}
+
+/**
+ * tod_to_ns - convert a TOD format value to nanoseconds
+ * @todval: to be converted TOD format value
+ * Returns: number of nanoseconds that correspond to the TOD format value
+ *
+ * Converting a 64 Bit TOD format value to nanoseconds means that the value
+ * must be divided by 4.096. In order to achieve that we multiply with 125
+ * and divide by 512:
+ *
+ *    ns = (todval * 125) >> 9;
+ *
+ * In order to avoid an overflow with the multiplication we can rewrite this.
+ * With a split todval == 2^9 * th + tl (th upper 55 bits, tl lower 9 bits)
+ * we end up with
+ *
+ *    ns = ((2^9 * th + tl) * 125 ) >> 9;
+ * -> ns = (th * 125) + ((tl * 125) >> 9);
+ *
+ */
+static inline uint64_t tod_to_ns(uint64_t todval)
+{
+	return ((todval >> 9) * 125) + (((todval & 0x1ff) * 125) >> 9);
+}
+
+
+uint64_t time_get_ns(void);
+uint64_t time_get_s(void);
+#endif
diff --git a/s390x/Makefile b/s390x/Makefile
index 82c4f15..afee4c9 100644
--- a/s390x/Makefile
+++ b/s390x/Makefile
@@ -43,6 +43,7 @@  cflatobjs += lib/s390x/sclp.o
 cflatobjs += lib/s390x/sclp-console.o
 cflatobjs += lib/s390x/interrupt.o
 cflatobjs += lib/s390x/mmu.o
+cflatobjs += lib/s390x/time.o
 
 OBJDIRS += lib/s390x