[Skiboot] [PATCH] Configure CAPP timebase.
Philippe Bergheaud
felix at linux.vnet.ibm.com
Fri Jun 19 22:52:54 AEST 2015
Extend the OPAL call phb3_set_capi_mode to configure CAPP timebase.
Inform Linux with the device tree property "ibm,capp-timebase-sync.
Signed-off-by: Philippe Bergheaud <felix at linux.vnet.ibm.com>
---
hw/chiptod.c | 159 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
hw/phb3.c | 10 +++
include/capp.h | 2 +
include/chiptod.h | 1 +
4 files changed, 171 insertions(+), 1 deletions(-)
diff --git a/hw/chiptod.c b/hw/chiptod.c
index 18c4847..6a79902 100644
--- a/hw/chiptod.c
+++ b/hw/chiptod.c
@@ -15,11 +15,12 @@
*/
/*
- * Handle ChipTOD chip & configure core timebases
+ * Handle ChipTOD chip & configure core and CAPP timebases
*/
#include <skiboot.h>
#include <chiptod.h>
#include <chip.h>
+#include <capp.h>
#include <xscom.h>
#include <io.h>
#include <cpu.h>
@@ -1010,3 +1011,159 @@ void chiptod_init(void)
op_display(OP_LOG, OP_MOD_CHIPTOD, 4);
}
+
+/* CAPP timebase sync */
+
+static bool chiptod_capp_reset_tb_errors(uint32_t chip_id)
+{
+ 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;
+ tfmr |= SPR_TFMR_TBST_CORRUPT;
+ tfmr |= SPR_TFMR_TFMR_CORRUPT;
+
+ /* Write CAPP TFMR */
+ xscom_write(chip_id, CAPP_TFMR, tfmr);
+
+ /* We have to write "Clear TB Errors" again */
+ tfmr = base_tfmr | SPR_TFMR_CLEAR_TB_ERRORS;
+ /* Write CAPP TFMR */
+ xscom_write(chip_id, CAPP_TFMR, tfmr);
+
+ do {
+ if (++timeout >= TIMEOUT_LOOPS) {
+ prerror("CAPP: TB error reset timeout !\n");
+ return false;
+ }
+ /* Read CAPP TFMR */
+ xscom_read(chip_id, CAPP_TFMR, &tfmr);
+ if (tfmr & SPR_TFMR_TFMR_CORRUPT) {
+ prerror("CAPP: TB error reset: corrupt TFMR!\n");
+ return false;
+ }
+ } while (tfmr & SPR_TFMR_CLEAR_TB_ERRORS);
+ return true;
+}
+
+static bool chiptod_capp_mod_tb(uint32_t chip_id)
+{
+ uint64_t timeout = 0;
+ uint64_t tfmr;
+
+ /* Switch CAPP timebase to "Not Set" state */
+ tfmr = base_tfmr | SPR_TFMR_LOAD_TOD_MOD;
+ xscom_write(chip_id, CAPP_TFMR, tfmr);
+ do {
+ if (++timeout >= (TIMEOUT_LOOPS*2)) {
+ prerror("CAPP: TB \"Not Set\" timeout\n");
+ return false;
+ }
+ xscom_read(chip_id, CAPP_TFMR, &tfmr);
+ if (tfmr & SPR_TFMR_TFMR_CORRUPT) {
+ prerror("CAPP: TB \"Not Set\" TFMR corrupt\n");
+ return false;
+ }
+ if (GETFIELD(SPR_TFMR_TBST_ENCODED, tfmr) == 9) {
+ prerror("CAPP: TB \"Not Set\" TOD in error state\n");
+ return false;
+ }
+ } while (tfmr & SPR_TFMR_LOAD_TOD_MOD);
+
+ return true;
+}
+
+static bool chiptod_wait_for_chip_sync(void)
+{
+ uint64_t tfmr;
+ uint64_t timeout = 0;
+
+ /* Read core TFMR, mask bit 42, write core TFMR back */
+ tfmr = mfspr(SPR_TFMR);
+ tfmr &= ~SPR_TFMR_TB_SYNC_OCCURED;
+ mtspr(SPR_TFMR, tfmr);
+
+ /* Read core TFMR until the TB sync occurred */
+ do {
+ if (++timeout >= TIMEOUT_LOOPS) {
+ prerror("CHIPTOD: No sync pulses\n");
+ return false;
+ }
+ tfmr = mfspr(SPR_TFMR);
+ } while (!(tfmr & SPR_TFMR_TB_SYNC_OCCURED));
+ return true;
+}
+
+static bool chiptod_capp_check_tb_running(uint32_t chip_id)
+{
+ uint64_t tfmr;
+ uint64_t timeout = 0;
+
+ /* Read CAPP TFMR until TB becomes valid */
+ do {
+ if (++timeout >= (TIMEOUT_LOOPS*2)) {
+ prerror("CAPP: TB Invalid!\n");
+ return false;
+ }
+ xscom_read(chip_id, CAPP_TFMR, &tfmr);
+ if (tfmr & SPR_TFMR_TFMR_CORRUPT) {
+ prerror("CAPP: TFMR corrupt!\n");
+ return false;
+ }
+ } while (!(tfmr & SPR_TFMR_TB_VALID));
+ return true;
+}
+
+bool chiptod_capp_timebase_sync(uint32_t chip_id)
+{
+ uint64_t tfmr;
+ uint64_t capp_tb;
+ int64_t delta;
+ unsigned int retry = 0;
+
+ /* Set CAPP TFMR to base tfmr value */
+ xscom_write(chip_id, CAPP_TFMR, base_tfmr);
+
+ /* Reset CAPP TB errors before attempting the sync */
+ if (!chiptod_capp_reset_tb_errors(chip_id))
+ return false;
+
+ /* Switch CAPP TB to "Not Set" state */
+ if (!chiptod_capp_mod_tb(chip_id))
+ return false;
+
+ /* Sync CAPP TB with core TB, retry while difference > 16usecs */
+ do {
+ if (retry++ > 5) {
+ prerror("CAPP: TB sync: giving up!\n");
+ return false;
+ }
+
+ /* Make CAPP ready to get the TB, wait for chip sync */
+ tfmr = base_tfmr | SPR_TFMR_MOVE_CHIP_TOD_TO_TB;
+ xscom_write(chip_id, CAPP_TFMR, tfmr);
+ if (!chiptod_wait_for_chip_sync())
+ return false;
+
+ /* Set CAPP TB from core TB */
+ xscom_write(chip_id, CAPP_TB, mftb());
+
+ /* Wait for CAPP TFMR tb_valid bit */
+ if (!chiptod_capp_check_tb_running(chip_id))
+ return false;
+
+ /* Read CAPP TB, read core TB, compare */
+ xscom_read(chip_id, CAPP_TB, &capp_tb);
+ delta = mftb() - capp_tb;
+ if (delta < 0)
+ delta = -delta;
+ } while (tb_to_usecs(delta) > 16);
+
+ return true;
+}
diff --git a/hw/phb3.c b/hw/phb3.c
index 9ffb449..b3c6870 100644
--- a/hw/phb3.c
+++ b/hw/phb3.c
@@ -46,6 +46,7 @@
#include <capp.h>
#include <fsp.h>
#include <chip.h>
+#include <chiptod.h>
/* Enable this to disable error interrupts for debug purposes */
#undef DISABLE_ERR_INTS
@@ -3331,6 +3332,12 @@ static int64_t phb3_set_capi_mode(struct phb *phb, uint64_t mode,
phb3_init_capp_errors(p);
phb3_init_capp_regs(p);
+
+ if (!chiptod_capp_timebase_sync(p->chip_id)) {
+ PHBERR(p, "CAPP: Failed to sync timebase\n");
+ return OPAL_HARDWARE;
+ }
+
return OPAL_SUCCESS;
}
@@ -4087,6 +4094,9 @@ static void phb3_add_properties(struct phb3 *p)
*/
dt_add_property_string(np, "ibm,msi-eoi-method", "ioda2");
+ /* Indicate to Linux that CAPP timebase sync is supported */
+ dt_add_property_string(np, "ibm,capp-timebase-sync", NULL);
+
/* The interrupt maps will be generated in the RC node by the
* PCI code based on the content of this structure:
*/
diff --git a/include/capp.h b/include/capp.h
index 4b53e37..d9275ec 100644
--- a/include/capp.h
+++ b/include/capp.h
@@ -74,6 +74,8 @@ enum capp_reg {
#define CANNED_PRESP_MAP2 0x201301F
#define CAPP_ERR_STATUS_CTRL 0x201300E
#define FLUSH_SUE_STATE_MAP 0x201300F
+#define CAPP_TB 0x2013026
+#define CAPP_TFMR 0x2013027
#define CAPP_EPOCH_TIMER_CTRL 0x201302C
#define FLUSH_UOP_CONFIG1 0x2013803
#define FLUSH_UOP_CONFIG2 0x2013804
diff --git a/include/chiptod.h b/include/chiptod.h
index 43f1d3d..7d4157b 100644
--- a/include/chiptod.h
+++ b/include/chiptod.h
@@ -25,5 +25,6 @@ extern void chiptod_init(void);
extern bool chiptod_wakeup_resync(void);
extern int chiptod_recover_tb_errors(void);
extern void chiptod_reset_tb(void);
+extern bool chiptod_capp_timebase_sync(uint32_t chip_id);
#endif /* __CHIPTOD_H */
--
1.7.2.5
More information about the Skiboot
mailing list