summaryrefslogtreecommitdiff
path: root/arch/s390/boot/startup.c
diff options
context:
space:
mode:
authorHeiko Carstens <hca@linux.ibm.com>2025-02-07 15:48:59 +0100
committerVasily Gorbik <gor@linux.ibm.com>2025-03-04 17:18:06 +0100
commitf931f67cfc274682aecc9f727eecc89779fc47b7 (patch)
tree4d92c5a78d8ca293f7c5bb44bf43cf1061a408c3 /arch/s390/boot/startup.c
parenta1a8da0dec77e0149b482698a2c1daab3a02ef7a (diff)
s390/time: Convert MACHINE_HAS_SCC to machine_has_scc()
Use static branch(es) to implement and use machine_has_scc() instead of a runtime check via MACHINE_HAS_SCC. This comes with a cleanup of early time initialization: the initial tod_clock_base value is now passed via the bootdata mechanism, instead of using absolute lowcore as transport vehicle from the decompressor to the kernel. Also the early tod clock initialization is moved to the decompressor which allows to use a static branch with machine_has_scc() within the kernel. Reviewed-by: Vasily Gorbik <gor@linux.ibm.com> Signed-off-by: Heiko Carstens <hca@linux.ibm.com> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
Diffstat (limited to 'arch/s390/boot/startup.c')
-rw-r--r--arch/s390/boot/startup.c24
1 files changed, 24 insertions, 0 deletions
diff --git a/arch/s390/boot/startup.c b/arch/s390/boot/startup.c
index 8081f06ad258..1c7367a338cd 100644
--- a/arch/s390/boot/startup.c
+++ b/arch/s390/boot/startup.c
@@ -10,6 +10,7 @@
#include <asm/machine.h>
#include <asm/cpu_mf.h>
#include <asm/setup.h>
+#include <asm/timex.h>
#include <asm/kasan.h>
#include <asm/kexec.h>
#include <asm/sclp.h>
@@ -35,6 +36,8 @@ unsigned long __bootdata_preserved(max_mappable);
unsigned long __bootdata_preserved(page_noexec_mask);
unsigned long __bootdata_preserved(segment_noexec_mask);
unsigned long __bootdata_preserved(region_noexec_mask);
+union tod_clock __bootdata_preserved(tod_clock_base);
+u64 __bootdata_preserved(clock_comparator_max) = -1UL;
u64 __bootdata_preserved(stfle_fac_list[16]);
struct oldmem_data __bootdata_preserved(oldmem_data);
@@ -46,6 +49,20 @@ void error(char *x)
disabled_wait();
}
+static void reset_tod_clock(void)
+{
+ union tod_clock clk;
+
+ if (store_tod_clock_ext_cc(&clk) == 0)
+ return;
+ /* TOD clock not running. Set the clock to Unix Epoch. */
+ if (set_tod_clock(TOD_UNIX_EPOCH) || store_tod_clock_ext_cc(&clk))
+ disabled_wait();
+ memset(&tod_clock_base, 0, sizeof(tod_clock_base));
+ tod_clock_base.tod = TOD_UNIX_EPOCH;
+ get_lowcore()->last_update_clock = TOD_UNIX_EPOCH;
+}
+
static void detect_facilities(void)
{
if (cpu_has_edat1())
@@ -60,6 +77,13 @@ static void detect_facilities(void)
}
if (IS_ENABLED(CONFIG_PCI) && test_facility(153))
set_machine_feature(MFEATURE_PCI_MIO);
+ reset_tod_clock();
+ if (test_facility(139) && (tod_clock_base.tod >> 63)) {
+ /* Enable signed clock comparator comparisons */
+ set_machine_feature(MFEATURE_SCC);
+ clock_comparator_max = -1UL >> 1;
+ local_ctl_set_bit(0, CR0_CLOCK_COMPARATOR_SIGN_BIT);
+ }
}
static int cmma_test_essa(void)