summaryrefslogtreecommitdiffstats
path: root/hw/chiptod.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/chiptod.c')
-rw-r--r--hw/chiptod.c685
1 files changed, 685 insertions, 0 deletions
diff --git a/hw/chiptod.c b/hw/chiptod.c
new file mode 100644
index 00000000..e24d9667
--- /dev/null
+++ b/hw/chiptod.c
@@ -0,0 +1,685 @@
+/* Copyright 2013-2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Handle ChipTOD chip & configure core timebases
+ */
+#include <skiboot.h>
+#include <chiptod.h>
+#include <xscom.h>
+#include <io.h>
+#include <cpu.h>
+#include <timebase.h>
+
+//#define DBG(fmt...) printf("CHIPTOD: " fmt)
+#define DBG(fmt...) do { } while(0)
+
+/* TOD chip XSCOM addresses */
+#define TOD_TTYPE_0 0x00040011
+#define TOD_TTYPE_1 0x00040012 /* PSS switch */
+#define TOD_TTYPE_2 0x00040013 /* Enable step checkers */
+#define TOD_TTYPE_3 0x00040014 /* Request TOD */
+#define TOD_TTYPE_4 0x00040015 /* Send TOD */
+#define TOD_TTYPE_5 0x00040016 /* Invalidate TOD */
+#define TOD_CHIPTOD_TO_TB 0x00040017
+#define TOD_LOAD_TOD_MOD 0x00040018
+#define TOD_CHIPTOD_VALUE 0x00040020
+#define TOD_CHIPTOD_LOAD_TB 0x00040021
+#define TOD_CHIPTOD_FSM 0x00040024
+
+/* -- TOD PIB Master reg -- */
+#define TOD_PIB_MASTER 0x00040027
+#define TOD_PIBM_ADDR_CFG_MCAST PPC_BIT(25)
+#define TOD_PIBM_ADDR_CFG_SLADDR_MASK PPC_BITMASK(26,31)
+#define TOD_PIBM_ADDR_CFG_SLADDR_LSH PPC_BITLSHIFT(31)
+
+/* -- TOD Error interrupt register -- */
+#define TOD_ERROR 0x00040030
+/* SYNC errors */
+#define TOD_ERR_CRMO_PARITY PPC_BIT(0)
+#define TOD_ERR_OSC0_PARITY PPC_BIT(1)
+#define TOD_ERR_OSC1_PARITY PPC_BIT(2)
+#define TOD_ERR_CRITC_PARITY PPC_BIT(13)
+#define TOD_ERR_PSS_HAMMING_DISTANCE PPC_BIT(18)
+#define TOD_ERR_DELAY_COMPL_PARITY PPC_BIT(22)
+/* CNTR errors */
+#define TOD_ERR_CTCR_PARITY PPC_BIT(32)
+#define TOD_ERR_TOD_SYNC_CHECK PPC_BIT(33)
+#define TOD_ERR_TOD_FSM_PARITY PPC_BIT(34)
+#define TOD_ERR_TOD_REGISTER_PARITY PPC_BIT(35)
+#define TOD_ERR_OVERFLOW_YR2042 PPC_BIT(36)
+#define TOD_ERR_TOD_WOF_LSTEP_PARITY PPC_BIT(37)
+#define TOD_ERR_TTYPE0_RECVD PPC_BIT(38)
+#define TOD_ERR_TTYPE1_RECVD PPC_BIT(39)
+#define TOD_ERR_TTYPE2_RECVD PPC_BIT(40)
+#define TOD_ERR_TTYPE3_RECVD PPC_BIT(41)
+#define TOD_ERR_TTYPE4_RECVD PPC_BIT(42)
+#define TOD_ERR_TTYPE5_RECVD PPC_BIT(43)
+
+/* Magic TB value. One step cycle ahead of sync */
+#define INIT_TB 0x000000000001ff0
+
+/* Number of iterations for the various timeouts */
+#define TIMEOUT_LOOPS 20000000
+
+static enum chiptod_type {
+ chiptod_unknown,
+ chiptod_p7,
+ chiptod_p8
+} chiptod_type;
+
+static int32_t chiptod_primary = -1;
+static int32_t chiptod_secondary = -1;
+
+/* The base TFMR value is the same for the whole machine
+ * for now as far as I can tell
+ */
+static uint64_t base_tfmr;
+
+/*
+ * For now, we use a global lock for runtime chiptod operations,
+ * eventually make this a per-core lock for wakeup rsync and
+ * take all of them for RAS cases.
+ */
+static struct lock chiptod_lock = LOCK_UNLOCKED;
+
+static void chiptod_setup_base_tfmr(void)
+{
+ struct dt_node *cpu = this_cpu()->node;
+ uint64_t core_freq, tod_freq;
+ uint64_t mcbs;
+
+ base_tfmr = SPR_TFMR_TB_ECLIPZ;
+
+ /* Get CPU and TOD freqs in Hz */
+ if (dt_has_node_property(cpu,"ibm,extended-clock-frequency", NULL))
+ core_freq = dt_prop_get_u64(cpu,"ibm,extended-clock-frequency");
+ else
+ core_freq = dt_prop_get_u32(cpu, "clock-frequency");
+ tod_freq = 32000000;
+
+ /* Calculate the "Max Cycles Between Steps" value according
+ * to the magic formula:
+ *
+ * mcbs = (core_freq * max_jitter_factor) / (4 * tod_freq) / 100;
+ *
+ * The max jitter factor is set to 240 based on what pHyp uses.
+ */
+ mcbs = (core_freq * 240) / (4 * tod_freq) / 100;
+ printf("CHIPTOD: Calculated MCBS is 0x%llx (Cfreq=%lld Tfreq=%lld)\n",
+ mcbs, core_freq, tod_freq);
+
+ /* Bake that all into TFMR */
+ base_tfmr = SETFIELD(SPR_TFMR_MAX_CYC_BET_STEPS, base_tfmr, mcbs);
+ base_tfmr = SETFIELD(SPR_TFMR_N_CLKS_PER_STEP, base_tfmr, 0);
+ base_tfmr = SETFIELD(SPR_TFMR_SYNC_BIT_SEL, base_tfmr, 4);
+}
+
+static bool chiptod_mod_tb(void)
+{
+ uint64_t tfmr = base_tfmr;
+ uint64_t timeout = 0;
+
+ /* Switch timebase to "Not Set" state */
+ mtspr(SPR_TFMR, tfmr | SPR_TFMR_LOAD_TOD_MOD);
+ do {
+ if (++timeout >= (TIMEOUT_LOOPS*2)) {
+ prerror("CHIPTOD: TB \"Not Set\" timeout\n");
+ return false;
+ }
+ tfmr = mfspr(SPR_TFMR);
+ if (tfmr & SPR_TFMR_TFMR_CORRUPT) {
+ prerror("CHIPTOD: TB \"Not Set\" TFMR corrupt\n");
+ return false;
+ }
+ if (GETFIELD(SPR_TFMR_TBST_ENCODED, tfmr) == 9) {
+ prerror("CHIPTOD: TB \"Not Set\" TOD in error state\n");
+ return false;
+ }
+ } while(tfmr & SPR_TFMR_LOAD_TOD_MOD);
+
+ return true;
+}
+
+static bool chiptod_interrupt_check(void)
+{
+ uint64_t tfmr = mfspr(SPR_TFMR);
+ uint64_t timeout = 0;
+
+ do {
+ if (++timeout >= TIMEOUT_LOOPS) {
+ prerror("CHIPTOD: Interrupt check fail\n");
+ return false;
+ }
+ tfmr = mfspr(SPR_TFMR);
+ if (tfmr & SPR_TFMR_TFMR_CORRUPT) {
+ prerror("CHIPTOD: Interrupt check TFMR corrupt !\n");
+ return false;
+ }
+ } while(tfmr & SPR_TFMR_CHIP_TOD_INTERRUPT);
+
+ return true;
+}
+
+static bool chiptod_poll_running(void)
+{
+ uint64_t timeout = 0;
+ uint64_t tval;
+
+ /* Chip TOD running check */
+ do {
+ if (++timeout >= TIMEOUT_LOOPS) {
+ prerror("CHIPTOD: Running check fail timeout\n");
+ return false;
+ }
+ if (xscom_readme(TOD_CHIPTOD_FSM, &tval) != 0) {
+ prerror("CHIPTOD: XSCOM error polling run\n");
+ return false;
+ }
+ } while(!(tval & 0x0800000000000000UL));
+
+ return true;
+}
+
+static bool chiptod_to_tb(void)
+{
+ uint64_t tval, tfmr, tvbits;
+ uint64_t timeout = 0;
+
+ /* Tell the ChipTOD about our fabric address
+ *
+ * The pib_master value is calculated from the CPU core ID, given in
+ * the PIR. Because we have different core/thread arrangements in the
+ * PIR between p7 and p8, we need to do the calculation differently.
+ *
+ * p7: 0b00001 || 3-bit core id
+ * p8: 0b0001 || 4-bit core id
+ */
+
+ if (xscom_readme(TOD_PIB_MASTER, &tval) != 0) {
+ prerror("CHIPTOD: XSCOM error reading PIB_MASTER\n");
+ return false;
+ }
+ if (chiptod_type == chiptod_p8) {
+ tvbits = (this_cpu()->pir >> 3) & 0xf;
+ tvbits |= 0x10;
+ } else {
+ tvbits = (this_cpu()->pir >> 2) & 0x7;
+ tvbits |= 0x08;
+ }
+ tval &= ~TOD_PIBM_ADDR_CFG_MCAST;
+ tval = SETFIELD(TOD_PIBM_ADDR_CFG_SLADDR, tval, tvbits);
+ if (xscom_writeme(TOD_PIB_MASTER, tval) != 0) {
+ prerror("CHIPTOD: XSCOM error writing PIB_MASTER\n");
+ return false;
+ }
+
+ /* Make us ready to get the TB from the chipTOD */
+ mtspr(SPR_TFMR, base_tfmr | SPR_TFMR_MOVE_CHIP_TOD_TO_TB);
+
+ /* Tell the ChipTOD to send it */
+ if (xscom_writeme(TOD_CHIPTOD_TO_TB, (1ULL << 63)) != 0) {
+ prerror("CHIPTOD: XSCOM error writing CHIPTOD_TO_TB\n");
+ return false;
+ }
+
+ /* Wait for it to complete */
+ timeout = 0;
+ do {
+ if (++timeout >= TIMEOUT_LOOPS) {
+ prerror("CHIPTOD: Chip to TB timeout\n");
+ return false;
+ }
+ tfmr = mfspr(SPR_TFMR);
+ if (tfmr & SPR_TFMR_TFMR_CORRUPT) {
+ prerror("CHIPTOD: MoveToTB: corrupt TFMR !\n");
+ return false;
+ }
+ } while(tfmr & SPR_TFMR_MOVE_CHIP_TOD_TO_TB);
+
+ return true;
+}
+
+static bool chiptod_check_tb_running(void)
+{
+ /* We used to wait for two SYNC pulses in TFMR but that
+ * doesn't seem to occur in sim, so instead we use a
+ * method similar to what pHyp does which is to check for
+ * TFMR SPR_TFMR_TB_VALID and not SPR_TFMR_TFMR_CORRUPT
+ */
+#if 0
+ uint64_t tfmr, timeout;
+ unsigned int i;
+
+ for (i = 0; i < 2; i++) {
+ tfmr = mfspr(SPR_TFMR);
+ tfmr &= ~SPR_TFMR_TB_SYNC_OCCURED;
+ mtspr(SPR_TFMR, tfmr);
+ timeout = 0;
+ do {
+ if (++timeout >= TIMEOUT_LOOPS) {
+ prerror("CHIPTOD: No sync pulses\n");
+ return false;
+ }
+ tfmr = mfspr(SPR_TFMR);
+ } while(!(tfmr & SPR_TFMR_TB_SYNC_OCCURED));
+ }
+#else
+ uint64_t tfmr = mfspr(SPR_TFMR);
+
+ return (tfmr & SPR_TFMR_TB_VALID) &&
+ !(tfmr & SPR_TFMR_TFMR_CORRUPT);
+#endif
+ return true;
+}
+
+static void chiptod_reset_tb_errors(void)
+{
+ uint64_t tfmr;
+ unsigned long timeout = 0;
+
+ /* Ask for automatic clear of errors */
+ tfmr = base_tfmr | SPR_TFMR_CLEAR_TB_ERRORS;
+
+ /* Additionally pHyp sets these (write-1-to-clear ?) */
+ tfmr |= SPR_TFMR_TB_MISSING_SYNC;
+ tfmr |= SPR_TFMR_TB_MISSING_STEP;
+ tfmr |= SPR_TFMR_TB_RESIDUE_ERR;
+ mtspr(SPR_TFMR, tfmr);
+
+ /* We have to write "Clear TB Errors" again */
+ tfmr = base_tfmr | SPR_TFMR_CLEAR_TB_ERRORS;
+ mtspr(SPR_TFMR, tfmr);
+
+ do {
+ if (++timeout >= TIMEOUT_LOOPS) {
+ /* Don't actually do anything on error for
+ * now ... not much we can do, panic maybe ?
+ */
+ prerror("CHIPTOD: TB error reset timeout !\n");
+ return;
+ }
+ tfmr = mfspr(SPR_TFMR);
+ if (tfmr & SPR_TFMR_TFMR_CORRUPT) {
+ prerror("CHIPTOD: TB error reset: corrupt TFMR !\n");
+ return;
+ }
+ } while(tfmr & SPR_TFMR_CLEAR_TB_ERRORS);
+}
+
+static void chiptod_cleanup_thread_tfmr(void)
+{
+ uint64_t tfmr = base_tfmr;
+
+ tfmr |= SPR_TFMR_PURR_PARITY_ERR;
+ tfmr |= SPR_TFMR_SPURR_PARITY_ERR;
+ tfmr |= SPR_TFMR_DEC_PARITY_ERR;
+ tfmr |= SPR_TFMR_TFMR_CORRUPT;
+ tfmr |= SPR_TFMR_PURR_OVERFLOW;
+ tfmr |= SPR_TFMR_SPURR_OVERFLOW;
+ mtspr(SPR_TFMR, tfmr);
+}
+
+static void chiptod_reset_tod_errors(void)
+{
+ uint64_t terr;
+
+ /*
+ * At boot, we clear the errors that the firmware is
+ * supposed to handle. List provided by the pHyp folks.
+ */
+
+ terr = TOD_ERR_CRITC_PARITY;
+ terr |= TOD_ERR_PSS_HAMMING_DISTANCE;
+ terr |= TOD_ERR_DELAY_COMPL_PARITY;
+ terr |= TOD_ERR_CTCR_PARITY;
+ terr |= TOD_ERR_TOD_SYNC_CHECK;
+ terr |= TOD_ERR_TOD_FSM_PARITY;
+ terr |= TOD_ERR_TOD_REGISTER_PARITY;
+
+ if (xscom_writeme(TOD_ERROR, terr) != 0) {
+ prerror("CHIPTOD: XSCOM error writing TOD_ERROR !\n");
+ /* Not much we can do here ... abort ? */
+ }
+}
+
+static void chiptod_sync_master(void *data)
+{
+ bool *result = data;
+
+ printf("CHIPTOD: Master sync on CPU PIR 0x%04x...\n", this_cpu()->pir);
+
+ /* Apply base tfmr */
+ mtspr(SPR_TFMR, base_tfmr);
+
+ /* From recipe provided by pHyp folks, reset various errors
+ * before attempting the sync
+ */
+ chiptod_reset_tb_errors();
+
+ /* Cleanup thread tfmr bits */
+ chiptod_cleanup_thread_tfmr();
+
+ /* Reset errors in the chiptod itself */
+ chiptod_reset_tod_errors();
+
+ /* Switch timebase to "Not Set" state */
+ if (!chiptod_mod_tb())
+ goto error;
+ DBG("SYNC MASTER Step 2 TFMR=0x%016lx\n", mfspr(SPR_TFMR));
+
+ /* Chip TOD step checkers enable */
+ if (xscom_writeme(TOD_TTYPE_2, (1UL << 63)) != 0) {
+ prerror("CHIPTOD: XSCOM error enabling steppers\n");
+ goto error;
+ }
+
+ DBG("SYNC MASTER Step 3 TFMR=0x%016lx\n", mfspr(SPR_TFMR));
+
+ /* Chip TOD interrupt check */
+ if (!chiptod_interrupt_check())
+ goto error;
+ DBG("SYNC MASTER Step 4 TFMR=0x%016lx\n", mfspr(SPR_TFMR));
+
+ /* Switch local chiptod to "Not Set" state */
+ if (xscom_writeme(TOD_LOAD_TOD_MOD, (1UL << 63)) != 0) {
+ prerror("CHIPTOD: XSCOM error sending LOAD_TOD_MOD\n");
+ goto error;
+ }
+
+ /* Switch all remote chiptod to "Not Set" state */
+ if (xscom_writeme(TOD_TTYPE_5, (1UL << 63)) != 0) {
+ prerror("CHIPTOD: XSCOM error sending TTYPE_5\n");
+ goto error;
+ }
+
+ /* Chip TOD load initial value */
+ if (xscom_writeme(TOD_CHIPTOD_LOAD_TB, INIT_TB) != 0) {
+ prerror("CHIPTOD: XSCOM error setting init TB\n");
+ goto error;
+ }
+
+ DBG("SYNC MASTER Step 5 TFMR=0x%016lx\n", mfspr(SPR_TFMR));
+
+ if (!chiptod_poll_running())
+ goto error;
+ DBG("SYNC MASTER Step 6 TFMR=0x%016lx\n", mfspr(SPR_TFMR));
+
+ /* Move chiptod value to core TB */
+ if (!chiptod_to_tb())
+ goto error;
+ DBG("SYNC MASTER Step 7 TFMR=0x%016lx\n", mfspr(SPR_TFMR));
+
+ /* Send local chip TOD to all chips TOD */
+ if (xscom_writeme(TOD_TTYPE_4, (1ULL << 63)) != 0) {
+ prerror("CHIPTOD: XSCOM error sending TTYPE_4\n");
+ goto error;
+ }
+
+ /* Check if TB is running */
+ if (!chiptod_check_tb_running())
+ goto error;
+
+ DBG("Master sync completed, TB=%lx\n", mfspr(SPR_TBRL));
+
+ /*
+ * A little delay to make sure the remote chips get up to
+ * speed before we start syncing them.
+ *
+ * We have to do it here because we know our TB is running
+ * while the boot thread TB might not yet.
+ */
+ time_wait_ms(1);
+
+ *result = true;
+ return;
+ error:
+ prerror("CHIPTOD: Master sync failed! TFMR=0x%016lx\n",
+ mfspr(SPR_TFMR));
+ *result = false;
+}
+
+static void chiptod_sync_slave(void *data)
+{
+ bool *result = data;
+
+ /* Only get primaries, not threads */
+ if (this_cpu()->is_secondary) {
+ /* On secondaries we just cleanup the TFMR */
+ chiptod_cleanup_thread_tfmr();
+ *result = true;
+ return;
+ }
+
+ printf("CHIPTOD: Slave sync on CPU PIR 0x%04x...\n", this_cpu()->pir);
+
+ /* Apply base tfmr */
+ mtspr(SPR_TFMR, base_tfmr);
+
+ /* From recipe provided by pHyp folks, reset various errors
+ * before attempting the sync
+ */
+ chiptod_reset_tb_errors();
+
+ /* Cleanup thread tfmr bits */
+ chiptod_cleanup_thread_tfmr();
+
+ /* Switch timebase to "Not Set" state */
+ if (!chiptod_mod_tb())
+ goto error;
+ DBG("SYNC SLAVE Step 2 TFMR=0x%016lx\n", mfspr(SPR_TFMR));
+
+ /* Chip TOD running check */
+ if (!chiptod_poll_running())
+ goto error;
+ DBG("SYNC SLAVE Step 3 TFMR=0x%016lx\n", mfspr(SPR_TFMR));
+
+ /* Chip TOD interrupt check */
+ if (!chiptod_interrupt_check())
+ goto error;
+ DBG("SYNC SLAVE Step 4 TFMR=0x%016lx\n", mfspr(SPR_TFMR));
+
+ /* Move chiptod value to core TB */
+ if (!chiptod_to_tb())
+ goto error;
+ DBG("SYNC SLAVE Step 5 TFMR=0x%016lx\n", mfspr(SPR_TFMR));
+
+ /* Check if TB is running */
+ if (!chiptod_check_tb_running())
+ goto error;
+
+ DBG("Slave sync completed, TB=%lx\n", mfspr(SPR_TBRL));
+
+ *result = true;
+ return;
+ error:
+ prerror("CHIPTOD: Slave sync failed ! TFMR=0x%016lx\n",
+ mfspr(SPR_TFMR));
+ *result = false;
+}
+
+bool chiptod_wakeup_resync(void)
+{
+ lock(&chiptod_lock);
+
+ /* Apply base tfmr */
+ mtspr(SPR_TFMR, base_tfmr);
+
+ /* From recipe provided by pHyp folks, reset various errors
+ * before attempting the sync
+ */
+ chiptod_reset_tb_errors();
+
+ /* Cleanup thread tfmr bits */
+ chiptod_cleanup_thread_tfmr();
+
+ /* Switch timebase to "Not Set" state */
+ if (!chiptod_mod_tb())
+ goto error;
+
+ /* Move chiptod value to core TB */
+ if (!chiptod_to_tb())
+ goto error;
+
+ unlock(&chiptod_lock);
+
+ return true;
+ error:
+ prerror("CHIPTOD: Resync failed ! TFMR=0x%16lx\n", mfspr(SPR_TFMR));
+ unlock(&chiptod_lock);
+ return false;
+}
+
+static int64_t opal_resync_timebase(void)
+{
+ if (!chiptod_wakeup_resync()) {
+ printf("OPAL: Resync timebase failed on CPU 0x%04x\n",
+ this_cpu()->pir);
+ return OPAL_HARDWARE;
+ }
+ return OPAL_SUCCESS;
+}
+opal_call(OPAL_RESYNC_TIMEBASE, opal_resync_timebase, 0);
+
+static void chiptod_print_tb(void *data __unused)
+{
+ printf("CHIPTOD: PIR 0x%04x TB=%lx\n",
+ this_cpu()->pir, mfspr(SPR_TBRL));
+}
+
+static bool chiptod_probe(u32 master_cpu)
+{
+ struct dt_node *np;
+
+ dt_for_each_compatible(dt_root, np, "ibm,power-chiptod") {
+ uint32_t chip;
+
+ /* Old DT has chip-id in chiptod node, newer only in the
+ * parent xscom bridge
+ */
+ chip = dt_get_chip_id(np);
+
+ if (dt_has_node_property(np, "primary", NULL)) {
+ chiptod_primary = chip;
+ if (dt_node_is_compatible(np,"ibm,power7-chiptod"))
+ chiptod_type = chiptod_p7;
+ if (dt_node_is_compatible(np,"ibm,power8-chiptod"))
+ chiptod_type = chiptod_p8;
+ }
+
+ if (dt_has_node_property(np, "secondary", NULL))
+ chiptod_secondary = chip;
+
+ }
+
+ /*
+ * If ChipTOD isn't found in the device-tree, we fallback
+ * based on the master CPU passed by OPAL boot since the
+ * FSP strips off the ChipTOD info from the HDAT when booting
+ * in OPAL mode :-(
+ */
+ if (chiptod_primary < 0) {
+ struct cpu_thread *t = find_cpu_by_pir(master_cpu);
+ printf("CHIPTOD: Cannot find a primary TOD in device-tree\n");
+ printf("CHIPTOD: Falling back to Master CPU: %d\n", master_cpu);
+ if (!t) {
+ prerror("CHIPTOD: NOT FOUND !\n");
+ return false;
+ }
+ chiptod_primary = t->chip_id;
+ switch(proc_gen) {
+ case proc_gen_p7:
+ chiptod_type = chiptod_p7;
+ return true;
+ case proc_gen_p8:
+ chiptod_type = chiptod_p8;
+ return true;
+ default:
+ break;
+ }
+ prerror("CHIPTOD: Unknown fallback CPU type !\n");
+ return false;
+ }
+ if (chiptod_type == chiptod_unknown) {
+ prerror("CHIPTOD: Unknown TOD type !\n");
+ return false;
+ }
+
+ return true;
+}
+
+void chiptod_init(u32 master_cpu)
+{
+ struct cpu_thread *cpu0, *cpu;
+ bool sres;
+
+ op_display(OP_LOG, OP_MOD_CHIPTOD, 0);
+
+ if (!chiptod_probe(master_cpu)) {
+ prerror("CHIPTOD: Failed ChipTOD detection !\n");
+ op_display(OP_FATAL, OP_MOD_CHIPTOD, 0);
+ abort();
+ }
+
+ op_display(OP_LOG, OP_MOD_CHIPTOD, 1);
+
+ /* Pick somebody on the primary */
+ cpu0 = find_cpu_by_chip_id(chiptod_primary);
+
+ /* Calculate the base TFMR value used for everybody */
+ chiptod_setup_base_tfmr();
+
+ printf("CHIPTOD: Base TFMR=0x%016llx\n", base_tfmr);
+
+ /* Schedule master sync */
+ sres = false;
+ cpu_wait_job(cpu_queue_job(cpu0, chiptod_sync_master, &sres), true);
+ if (!sres) {
+ op_display(OP_FATAL, OP_MOD_CHIPTOD, 2);
+ abort();
+ }
+
+ op_display(OP_LOG, OP_MOD_CHIPTOD, 2);
+
+ /* Schedule slave sync */
+ for_each_available_cpu(cpu) {
+ /* Skip master */
+ if (cpu == cpu0)
+ continue;
+
+ /* Queue job */
+ sres = false;
+ cpu_wait_job(cpu_queue_job(cpu, chiptod_sync_slave, &sres),
+ true);
+ if (!sres) {
+ op_display(OP_WARN, OP_MOD_CHIPTOD, 3|(cpu->pir << 8));
+
+ /* Disable threads */
+ cpu_disable_all_threads(cpu);
+ }
+ op_display(OP_LOG, OP_MOD_CHIPTOD, 3|(cpu->pir << 8));
+ }
+
+ /* Display TBs */
+ for_each_available_cpu(cpu) {
+ /* Only do primaries, not threads */
+ if (cpu->is_secondary)
+ continue;
+ cpu_wait_job(cpu_queue_job(cpu, chiptod_print_tb, NULL), true);
+ }
+
+ op_display(OP_LOG, OP_MOD_CHIPTOD, 4);
+}
OpenPOWER on IntegriCloud