aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPratik Rajesh Sampat <psampat@linux.ibm.com>2019-11-26 20:27:19 +0530
committerRam Pai <linuxram@us.ibm.com>2020-11-03 12:52:37 -0500
commitadb88829e5d69d6e7105a5f68f6e8009eff208ff (patch)
treeb52989126dec3e4eaf8d47dbdfc1a9c09838f5ef
parentd85f89355e0bbcb5875dc2ccdcdb7fe3ccf5f701 (diff)
downloadskiboot-adb88829e5d69d6e7105a5f68f6e8009eff208ff.zip
skiboot-adb88829e5d69d6e7105a5f68f6e8009eff208ff.tar.gz
skiboot-adb88829e5d69d6e7105a5f68f6e8009eff208ff.tar.bz2
self-save and self-restore
Signed-off-by: Ram Pai <linuxram@us.ibm.com> [merged all self-save/self-restore enabling patches] Signed-off-by: Pratik Rajesh Sampat <psampat@linux.ibm.com>
-rw-r--r--core/init.c6
-rw-r--r--doc/opal-api/opal-slw-self-save-reg-176.rst33
-rw-r--r--hw/slw.c425
-rw-r--r--hw/ultravisor.c2
-rw-r--r--include/opal-api.h3
-rw-r--r--include/p9_stop_api.H21
-rw-r--r--include/skiboot.h4
-rw-r--r--include/ultravisor.h2
-rw-r--r--libpore/p9_cpu_reg_restore_instruction.H1
-rw-r--r--libpore/p9_stop_api.C74
-rw-r--r--libpore/p9_stop_api.H2
-rw-r--r--libpore/p9_stop_data_struct.H4
-rw-r--r--libpore/p9_stop_util.H7
13 files changed, 549 insertions, 35 deletions
diff --git a/core/init.c b/core/init.c
index e737664..347cbc3 100644
--- a/core/init.c
+++ b/core/init.c
@@ -1194,9 +1194,6 @@ void __noreturn __nomcount main_cpu_entry(const void *fdt)
if (platform.seeprom_update)
platform.seeprom_update();
- /* Init SLW related stuff, including fastsleep */
- slw_init();
-
op_display(OP_LOG, OP_MOD_INIT, 0x0002);
/*
@@ -1277,6 +1274,9 @@ void __noreturn __nomcount main_cpu_entry(const void *fdt)
/* Init uiltravisor software */
init_uv();
+ /* Init SLW related stuff, including fastsleep */
+ slw_init();
+
/* Now release parts of memory nodes we haven't used ourselves... */
mem_region_release_unused();
diff --git a/doc/opal-api/opal-slw-self-save-reg-176.rst b/doc/opal-api/opal-slw-self-save-reg-176.rst
new file mode 100644
index 0000000..6a4e1a5
--- /dev/null
+++ b/doc/opal-api/opal-slw-self-save-reg-176.rst
@@ -0,0 +1,33 @@
+.. OPAL_SLW_SELF_SAVE_REG:
+
+OPAL_SLW_SELF_SAVE_REG
+======================
+
+.. code-block:: c
+
+ #define OPAL_SLW_SELF_SAVE_REG 176
+
+ int64_t opal_slw_self_save_reg(uint64_t cpu_pir, uint64_t sprn);
+
+:ref:`OPAL_SLW_SELF_SAVE_REG` is used to inform low-level firmware to save
+the current contents of the SPR before entering a state of loss and
+also restore the content back on waking up from a deep stop state.
+
+Parameters
+----------
+
+``uint64_t cpu_pir``
+ This parameter specifies the pir of the cpu for which the call is being made.
+``uint64_t sprn``
+ This parameter specifies the spr number as mentioned in p9_stop_api.H for
+ Power9 and p8_pore_table_gen_api.H for Power8.
+
+Returns
+-------
+
+:ref:`OPAL_UNSUPPORTED`
+ If spr restore is not supported by pore engine.
+:ref:`OPAL_PARAMETER`
+ Invalid handle for the pir/chip
+:ref:`OPAL_SUCCESS`
+ On success \ No newline at end of file
diff --git a/hw/slw.c b/hw/slw.c
index bb88f0f..5eb3d3a 100644
--- a/hw/slw.c
+++ b/hw/slw.c
@@ -22,12 +22,16 @@
#include <opal-api.h>
#include <nvram.h>
#include <sbe-p8.h>
+#include <bitmap.h>
#include <p9_stop_api.H>
#include <p8_pore_table_gen_api.H>
#include <sbe_xip_image.h>
#define MAX_RESET_PATCH_SIZE 64
+/* The POWER ISA mf/mtspr allows atmost 2048 SPRs. */
+#define SPR_BITMAP_LENGTH 2048
+#define DEFAULT_CPMMR_VALUE 0x2022000000000000
static uint32_t slw_saved_reset[MAX_RESET_PATCH_SIZE];
@@ -36,6 +40,53 @@ static bool slw_current_le = false;
enum wakeup_engine_states wakeup_engine_state = WAKEUP_ENGINE_NOT_PRESENT;
bool has_deep_states = false;
+#define HILE_BIT PPC_BIT(4)
+#define RADIX_BIT PPC_BIT(8)
+#define default_hid0_val (HILE_BIT | RADIX_BIT)
+/**
+ * The struct and SPR list is a subset of the libpore/p9_stop_api.c counterpart
+ */
+/**
+ * @brief summarizes attributes associated with a SPR register.
+ */
+typedef struct
+{
+ uint32_t iv_sprId;
+ bool iv_isThreadScope;
+ uint32_t iv_saveMaskPos;
+
+} StopSprReg_t;
+
+/**
+ * @brief a true in the table below means register is of scope thread
+ * whereas a false meanse register is of scope core.
+ * The number is the bit position on a uint32_t mask
+ */
+
+static const StopSprReg_t g_sprRegister[] =
+{
+ { P9_STOP_SPR_DAWR, true, 1 },
+ { P9_STOP_SPR_HSPRG0, true, 3 },
+ { P9_STOP_SPR_LDBAR, true, 4, },
+ { P9_STOP_SPR_LPCR, true, 5 },
+ { P9_STOP_SPR_PSSCR, true, 6 },
+ { P9_STOP_SPR_MSR, true, 7 },
+ { P9_STOP_SPR_HRMOR, false, 255 },
+ { P9_STOP_SPR_HID, false, 21 },
+ { P9_STOP_SPR_HMEER, false, 22 },
+ { P9_STOP_SPR_PMCR, false, 23 },
+ { P9_STOP_SPR_PTCR, false, 24 },
+ { P9_STOP_SPR_URMOR, false, 255 },
+ { P9_STOP_SPR_SMFCTRL, true, 28 },
+ { P9_STOP_SPR_USPRG0, true, 29 },
+ { P9_STOP_SPR_USPRG1, true, 30 },
+};
+
+static const uint32_t MAX_SPR_SUPPORTED = ARRAY_SIZE(g_sprRegister);
+uint32_t find_mask_self_save(const uint64_t sprn);
+bool self_restore_cpu_iterator(uint64_t sprn, uint64_t val);
+bool self_save_cpu_iterator(const uint64_t self_save_reg);
+
DEFINE_LOG_ENTRY(OPAL_RC_SLW_INIT, OPAL_PLATFORM_ERR_EVT, OPAL_SLW,
OPAL_PLATFORM_FIRMWARE, OPAL_PREDICTIVE_ERR_GENERAL,
OPAL_NA);
@@ -587,6 +638,116 @@ static struct cpu_idle_states power9_cpu_idle_states[] = {
};
/*
+ * Latency for Stop4 and 5 are bumped up so that cpuidle path is not exercised
+ * in the PEF environment, but the states are available to be exercised during a
+ * hotplug
+ */
+static struct cpu_idle_states power9_pef_cpu_idle_states[] = {
+ {
+ .name = "stop0_lite", /* Enter stop0 with no state loss */
+ .latency_ns = 1000,
+ .residency_ns = 10000,
+ .flags = 0*OPAL_PM_DEC_STOP \
+ | 0*OPAL_PM_TIMEBASE_STOP \
+ | 0*OPAL_PM_LOSE_USER_CONTEXT \
+ | 0*OPAL_PM_LOSE_HYP_CONTEXT \
+ | 0*OPAL_PM_LOSE_FULL_CONTEXT \
+ | 1*OPAL_PM_STOP_INST_FAST,
+ .pm_ctrl_reg_val = OPAL_PM_PSSCR_RL(0) \
+ | OPAL_PM_PSSCR_MTL(3) \
+ | OPAL_PM_PSSCR_TR(3),
+ .pm_ctrl_reg_mask = OPAL_PM_PSSCR_MASK },
+ {
+ .name = "stop0",
+ .latency_ns = 2000,
+ .residency_ns = 20000,
+ .flags = 0*OPAL_PM_DEC_STOP \
+ | 0*OPAL_PM_TIMEBASE_STOP \
+ | 1*OPAL_PM_LOSE_USER_CONTEXT \
+ | 0*OPAL_PM_LOSE_HYP_CONTEXT \
+ | 0*OPAL_PM_LOSE_FULL_CONTEXT \
+ | 1*OPAL_PM_STOP_INST_FAST,
+ .pm_ctrl_reg_val = OPAL_PM_PSSCR_RL(0) \
+ | OPAL_PM_PSSCR_MTL(3) \
+ | OPAL_PM_PSSCR_TR(3) \
+ | OPAL_PM_PSSCR_ESL \
+ | OPAL_PM_PSSCR_EC,
+ .pm_ctrl_reg_mask = OPAL_PM_PSSCR_MASK },
+
+ /* stop1_lite has been removed since it adds no additional benefit over stop0_lite */
+
+ {
+ .name = "stop1",
+ .latency_ns = 5000,
+ .residency_ns = 50000,
+ .flags = 0*OPAL_PM_DEC_STOP \
+ | 0*OPAL_PM_TIMEBASE_STOP \
+ | 1*OPAL_PM_LOSE_USER_CONTEXT \
+ | 0*OPAL_PM_LOSE_HYP_CONTEXT \
+ | 0*OPAL_PM_LOSE_FULL_CONTEXT \
+ | 1*OPAL_PM_STOP_INST_FAST,
+ .pm_ctrl_reg_val = OPAL_PM_PSSCR_RL(1) \
+ | OPAL_PM_PSSCR_MTL(3) \
+ | OPAL_PM_PSSCR_TR(3) \
+ | OPAL_PM_PSSCR_ESL \
+ | OPAL_PM_PSSCR_EC,
+ .pm_ctrl_reg_mask = OPAL_PM_PSSCR_MASK },
+ /*
+ * stop2_lite has been removed since currently it adds minimal benefit over stop2.
+ * However, the benefit is eclipsed by the time required to ungate the clocks
+ */
+
+ {
+ .name = "stop2",
+ .latency_ns = 10000,
+ .residency_ns = 100000,
+ .flags = 0*OPAL_PM_DEC_STOP \
+ | 0*OPAL_PM_TIMEBASE_STOP \
+ | 1*OPAL_PM_LOSE_USER_CONTEXT \
+ | 0*OPAL_PM_LOSE_HYP_CONTEXT \
+ | 0*OPAL_PM_LOSE_FULL_CONTEXT \
+ | 1*OPAL_PM_STOP_INST_FAST,
+ .pm_ctrl_reg_val = OPAL_PM_PSSCR_RL(2) \
+ | OPAL_PM_PSSCR_MTL(3) \
+ | OPAL_PM_PSSCR_TR(3) \
+ | OPAL_PM_PSSCR_ESL \
+ | OPAL_PM_PSSCR_EC,
+ .pm_ctrl_reg_mask = OPAL_PM_PSSCR_MASK },
+ {
+ .name = "stop4",
+ .latency_ns = 10000000,
+ .residency_ns = 100000000,
+ .flags = 0*OPAL_PM_DEC_STOP \
+ | 0*OPAL_PM_TIMEBASE_STOP \
+ | 1*OPAL_PM_LOSE_USER_CONTEXT \
+ | 1*OPAL_PM_LOSE_HYP_CONTEXT \
+ | 1*OPAL_PM_LOSE_FULL_CONTEXT \
+ | 1*OPAL_PM_STOP_INST_DEEP,
+ .pm_ctrl_reg_val = OPAL_PM_PSSCR_RL(4) \
+ | OPAL_PM_PSSCR_MTL(7) \
+ | OPAL_PM_PSSCR_TR(3) \
+ | OPAL_PM_PSSCR_ESL \
+ | OPAL_PM_PSSCR_EC,
+ .pm_ctrl_reg_mask = OPAL_PM_PSSCR_MASK },
+ {
+ .name = "stop5",
+ .latency_ns = 10000000,
+ .residency_ns = 100000000,
+ .flags = 0*OPAL_PM_DEC_STOP \
+ | 0*OPAL_PM_TIMEBASE_STOP \
+ | 1*OPAL_PM_LOSE_USER_CONTEXT \
+ | 1*OPAL_PM_LOSE_HYP_CONTEXT \
+ | 1*OPAL_PM_LOSE_FULL_CONTEXT \
+ | 1*OPAL_PM_STOP_INST_DEEP,
+ .pm_ctrl_reg_val = OPAL_PM_PSSCR_RL(5) \
+ | OPAL_PM_PSSCR_MTL(7) \
+ | OPAL_PM_PSSCR_TR(3) \
+ | OPAL_PM_PSSCR_ESL \
+ | OPAL_PM_PSSCR_EC,
+ .pm_ctrl_reg_mask = OPAL_PM_PSSCR_MASK },
+};
+
+/*
* Prior to Mambo.7.8.21, mambo did set the MSR correctly for lite stop
* states, so disable them for now.
*/
@@ -717,6 +878,171 @@ static void slw_late_init_p9(struct proc_chip *chip)
}
}
+uint32_t __attribute__((const))
+find_mask_self_save(const uint64_t sprn)
+{
+ uint32_t save_reg_vector = -1;
+ int index;
+ for (index = 0; index < MAX_SPR_SUPPORTED; ++index) {
+ if (sprn == (CpuReg_t) g_sprRegister[index].iv_sprId) {
+ save_reg_vector = PPC_BIT32(
+ g_sprRegister[index].iv_saveMaskPos);
+ break;
+ }
+ }
+ return save_reg_vector;
+}
+
+bool __attribute__((const))
+self_restore_cpu_iterator(uint64_t sprn, uint64_t val)
+{
+ struct cpu_thread *cpu;
+ struct proc_chip *chip;
+ int rc;
+
+ for_each_available_cpu(cpu) {
+ chip = get_chip(cpu->chip_id);
+ rc = p9_stop_save_cpureg((void *)chip->homer_base,
+ sprn,
+ val,
+ cpu->pir);
+ if (rc) {
+ prlog(PR_ERR,
+ "SLW: Failed to set spr %llx for CPU %x, RC=0x%x\n",
+ sprn, cpu->pir, rc);
+ return rc;
+ }
+ }
+ return rc;
+}
+
+bool __attribute__((const))
+self_save_cpu_iterator(const uint64_t self_save_reg)
+{
+ struct cpu_thread *cpu;
+ struct proc_chip *chip;
+ int rc;
+ uint32_t save_reg_vector;
+
+ for_each_available_cpu(cpu) {
+ chip = get_chip(cpu->chip_id);
+ save_reg_vector =
+ find_mask_self_save(self_save_reg);
+ if (save_reg_vector == -1)
+ return true;
+ rc = p9_stop_save_cpureg_control((void *) chip->homer_base,
+ cpu->pir,
+ save_reg_vector);
+ if (rc) {
+ prlog(PR_ERR,
+ "SLW: Failed to set spr %llx for CPU %x, RC=0x%x\n",
+ self_save_reg, cpu->pir, rc);
+ return rc;
+ }
+ prlog(PR_NOTICE, "SLW: Self save reg: 0x%llx\n",
+ self_save_reg);
+ }
+ return rc;
+}
+/* Add device tree properties to determine self-save | restore */
+void add_cpu_self_save_properties()
+{
+ int i, rc;
+ struct dt_node *self_restore, *self_save, *power_mgt;
+ bitmap_t *self_restore_map, *self_save_map;
+
+ const uint64_t self_restore_regs[] = {
+ 0x130, // HSPRG0
+ 0x13E, // LPCR
+ 0x151, // HMEER
+ 0x3F0, // HID0
+ 0x3F1, // HID1
+ 0x3F4, // HID4
+ 0x3F6, // HID5
+ 0x7D0, // MSR
+ 0x357 // PSCCR
+ };
+
+ const uint64_t self_save_regs[] = {
+ 0x130, // HSPRG0
+ 0x13E, // LPCR
+ 0x151, // HMEER
+ 0x7D0, // MSR
+ 0x1D0, //PTCR
+ 0x1F0, // USPRG0
+ 0x1F1, //USPRG1
+ 0x1FF, //SMFCTRL
+ 0x357 // PSCCR
+ };
+
+ self_save_map = zalloc(BITMAP_BYTES(SPR_BITMAP_LENGTH));
+ self_restore_map = zalloc(BITMAP_BYTES(SPR_BITMAP_LENGTH));
+
+ for (i = 0; i < ARRAY_SIZE(self_restore_regs); i++) {
+ if (is_msr_bit_set(MSR_S) && self_restore_regs[i] != P9_STOP_SPR_HID)
+ continue;
+ bitmap_set_bit(*self_restore_map, self_restore_regs[i]);
+ }
+
+ if (is_msr_bit_set(MSR_S)) {
+ rc = self_restore_cpu_iterator(P9_STOP_SPR_HID,
+ default_hid0_val);
+ if (rc)
+ goto bail;
+ if (uv_base_addr) {
+ rc = self_restore_cpu_iterator(P9_STOP_SPR_URMOR,
+ uv_base_addr);
+ if (rc)
+ goto bail;
+ } else {
+ prlog(PR_ERR,
+ "SLW: uv_base_addr is NULL\n");
+ goto bail;
+ }
+ }
+ for (i = 0; i < ARRAY_SIZE(self_save_regs); i++) {
+ bitmap_set_bit(*self_save_map, self_save_regs[i]);
+ if (!is_msr_bit_set(MSR_S))
+ continue;
+ rc = self_save_cpu_iterator(self_save_regs[i]);
+ if (rc)
+ goto bail;
+ }
+
+ power_mgt = dt_find_by_path(dt_root, "/ibm,opal/power-mgt");
+ if (!power_mgt) {
+ prerror("OCC: dt node /ibm,opal/power-mgt not found\n");
+ goto bail;
+ }
+
+ self_restore = dt_new(power_mgt, "self-restore");
+ if (!self_restore) {
+ prerror("OCC: Failed to create self restore node");
+ goto bail;
+ }
+ dt_add_property_string(self_restore, "status", "enabled");
+
+ dt_add_property(self_restore, "sprn-bitmask", *self_restore_map,
+ SPR_BITMAP_LENGTH / 8);
+
+ self_save = dt_new(power_mgt, "self-save");
+ if (!self_save) {
+ prerror("OCC: Failed to create self save node");
+ goto bail;
+ }
+ if (proc_gen == proc_gen_p9) {
+ dt_add_property_string(self_save, "status", "enabled");
+
+ dt_add_property(self_save, "sprn-bitmask", *self_save_map,
+ SPR_BITMAP_LENGTH / 8);
+ } else {
+ dt_add_property_string(self_save, "status", "disabled");
+ }
+bail:
+ free(self_save_map);
+ free(self_restore_map);
+}
+
/* Add device tree properties to describe idle states */
void add_cpu_idle_state_properties(void)
{
@@ -775,6 +1101,10 @@ void add_cpu_idle_state_properties(void)
if (proc_chip_quirks & QUIRK_MAMBO_CALLOUTS) {
states = power9_mambo_cpu_idle_states;
nr_states = ARRAY_SIZE(power9_mambo_cpu_idle_states);
+ } else if (is_msr_bit_set(MSR_S)) {
+ prlog(PR_EMERG, "pef state table is enabled\n");
+ states = power9_pef_cpu_idle_states;
+ nr_states = ARRAY_SIZE(power9_pef_cpu_idle_states);
} else {
states = power9_cpu_idle_states;
nr_states = ARRAY_SIZE(power9_cpu_idle_states);
@@ -783,6 +1113,10 @@ void add_cpu_idle_state_properties(void)
has_stop_inst = true;
stop_levels = dt_prop_get_u32_def(power_mgt,
"ibm,enabled-stop-levels", 0);
+ if (stop_levels != 0) {
+ prerror("HACK: stop levels enabled, forcing stop0 and stop1\n");
+ stop_levels = 0xc0000000;
+ }
if (!stop_levels) {
prerror("SLW: No stop levels available. Power saving is disabled!\n");
has_deep_states = false;
@@ -1393,6 +1727,19 @@ int64_t opal_slw_set_reg(uint64_t cpu_pir, uint64_t sprn, uint64_t val)
return OPAL_PARAMETER;
}
+ /*
+ * Return OPAL SUCCESS if we are in a PEF environment
+ * Self save does not currently work for HID0, hence we self
+ * restore and check against the default value as only LE Radix
+ * hypervisors can currently exist.
+ * Until there is a version that supports self save for HID,
+ * only Little Endian Radix can be supported
+ */
+ if (is_uv_present()) {
+ if (sprn == P9_STOP_SPR_HID && val != default_hid0_val)
+ return OPAL_UNSUPPORTED;
+ return OPAL_SUCCESS;
+ }
if (proc_gen == proc_gen_p9) {
if (!has_deep_states) {
prlog(PR_INFO, "SLW: Deep states not enabled\n");
@@ -1452,9 +1799,69 @@ int64_t opal_slw_set_reg(uint64_t cpu_pir, uint64_t sprn, uint64_t val)
opal_call(OPAL_SLW_SET_REG, opal_slw_set_reg, 3);
+int64_t opal_slw_self_save_reg(uint64_t cpu_pir, uint64_t sprn)
+{
+ struct cpu_thread * c = find_cpu_by_pir(cpu_pir);
+ struct proc_chip * chip;
+ int rc;
+ int index;
+ uint32_t save_reg_vector = 0;
+
+ if (!c) {
+ prlog(PR_DEBUG, "SLW: Unknown thread with pir %x\n",
+ (u32) cpu_pir);
+ return OPAL_PARAMETER;
+ }
+
+ chip = get_chip(c->chip_id);
+ if (!chip) {
+ prlog(PR_DEBUG, "SLW: Unknown chip for thread with pir %x\n",
+ (u32) cpu_pir);
+ return OPAL_PARAMETER;
+ }
+ if (proc_gen != proc_gen_p9 || !has_deep_states) {
+ prlog(PR_DEBUG, "SLW: Does not support deep states\n");
+ return OPAL_UNSUPPORTED;
+ }
+ if (wakeup_engine_state != WAKEUP_ENGINE_PRESENT) {
+ log_simple_error(&e_info(OPAL_RC_SLW_REG),
+ "SLW: wakeup_engine in bad state=%d chip=%x\n",
+ wakeup_engine_state, chip->id);
+ return OPAL_INTERNAL_ERROR;
+ }
+ for (index = 0; index < MAX_SPR_SUPPORTED; ++index) {
+ if (sprn == (CpuReg_t) g_sprRegister[index].iv_sprId) {
+ save_reg_vector = PPC_BIT32(
+ g_sprRegister[index].iv_saveMaskPos);
+ break;
+ }
+ }
+ if (save_reg_vector == 0)
+ return OPAL_INTERNAL_ERROR;
+ /*
+ * In a PEF environment, the values are saved prior to entering the
+ * secure environment, hence this can return a sucess
+ */
+ if (is_uv_present())
+ return OPAL_SUCCESS;
+ rc = p9_stop_save_cpureg_control((void *) chip->homer_base,
+ cpu_pir, save_reg_vector);
+
+ if (rc) {
+ log_simple_error(&e_info(OPAL_RC_SLW_REG),
+ "SLW: Failed to save vector %x for CPU %x\n",
+ save_reg_vector, c->pir);
+ return OPAL_INTERNAL_ERROR;
+ }
+ return OPAL_SUCCESS;
+}
+opal_call(OPAL_SLW_SELF_SAVE_REG, opal_slw_self_save_reg, 2);
+
void slw_init(void)
{
struct proc_chip *chip;
+ int i, rc;
+ u64 cpmmr_xscom_addr;
if (proc_chip_quirks & QUIRK_MAMBO_CALLOUTS) {
wakeup_engine_state = WAKEUP_ENGINE_NOT_PRESENT;
@@ -1479,5 +1886,23 @@ void slw_init(void)
slw_late_init_p9(chip);
}
}
+ /* Setting up CPPMR bits which allow the transition to HV from UV */
+ for_each_chip(chip) {
+ u8 nr_cores = get_available_nr_cores_in_chip(chip->id);
+
+ cpmmr_xscom_addr = 0x200f0106;
+ for (i = 0; i < nr_cores; i++) {
+ rc = xscom_write(chip->id, cpmmr_xscom_addr,
+ DEFAULT_CPMMR_VALUE | PPC_BIT(3));
+ if (rc) {
+ log_simple_error(&e_info(OPAL_RC_SLW_INIT),
+ "SLW: Failed to write to CPMMR\n");
+ }
+ /* Each core xscom address is offsetted */
+ cpmmr_xscom_addr += 0x1000000;
+ }
+ }
add_cpu_idle_state_properties();
+ if (has_deep_states)
+ add_cpu_self_save_properties();
}
diff --git a/hw/ultravisor.c b/hw/ultravisor.c
index ac49782..f764339 100644
--- a/hw/ultravisor.c
+++ b/hw/ultravisor.c
@@ -25,6 +25,7 @@ static size_t uv_image_size;
struct xz_decompress *uv_xz = NULL;
static struct uv_opal *uv_opal;
static int num_secure_ranges = 0;
+uint64_t uv_base_addr = 0;
struct memcons uv_memcons __section(".data.memcons") = {
.magic = MEMCONS_MAGIC,
@@ -361,6 +362,7 @@ void init_uv()
start:
uv_opal->uv_base_addr = uv_pef_reg;
+ uv_base_addr = uv_opal->uv_base_addr;
uv_opal->uv_mem = (__be64)&uv_memcons;
/*
* Place the uv_fdt 128MB below the top of secure memory.
diff --git a/include/opal-api.h b/include/opal-api.h
index ee66bbb..8f24ccc 100644
--- a/include/opal-api.h
+++ b/include/opal-api.h
@@ -222,7 +222,8 @@
#define OPAL_MPIPL_UPDATE 173
#define OPAL_MPIPL_REGISTER_TAG 174
#define OPAL_MPIPL_QUERY_TAG 175
-#define OPAL_LAST 175
+#define OPAL_SLW_SELF_SAVE_REG 179
+#define OPAL_LAST 179
#define QUIESCE_HOLD 1 /* Spin all calls at entry */
#define QUIESCE_REJECT 2 /* Fail all calls with OPAL_BUSY */
diff --git a/include/p9_stop_api.H b/include/p9_stop_api.H
index 79abd00..a58e639 100644
--- a/include/p9_stop_api.H
+++ b/include/p9_stop_api.H
@@ -34,6 +34,8 @@
///
/// @file p9_stop_api.H
/// @brief describes STOP API which create/manipulate STOP image.
+/// This header need not be consistent, however is a subset of the
+/// libpore/p9_stop_api.H counterpart
///
// *HWP HW Owner : Greg Still <stillgs@us.ibm.com>
// *HWP FW Owner : Prem Shanker Jha <premjha2@in.ibm.com>
@@ -63,6 +65,11 @@ typedef enum
P9_STOP_SPR_PMCR = 884, // core register
P9_STOP_SPR_HID = 1008, // core register
P9_STOP_SPR_MSR = 2000, // thread register
+ P9_STOP_SPR_PTCR = 464, // core register
+ P9_STOP_SPR_URMOR = 505, // core register
+ P9_STOP_SPR_USPRG0 = 496, // thread register
+ P9_STOP_SPR_USPRG1 = 497, // thread register
+ P9_STOP_SPR_SMFCTRL = 511, // thread register
} CpuReg_t;
/**
@@ -155,6 +162,20 @@ StopReturnCode_t p9_stop_save_scom( void* const i_pImage,
const ScomOperation_t i_operation,
const ScomSection_t i_section );
+/**
+ * @brief Facilitates self save and restore of a list of SPRs of a thread.
+ * @param[in] i_pImage points to the start of HOMER image of P9 chip.
+ * @param[in] i_pir PIR associated with thread
+ * @param[in] i_saveRegVector bit vector representing SPRs that needs to be restored.
+ * @return STOP_SAVE_SUCCESS if API succeeds, error code otherwise.
+ * @note SPR save vector is a bit vector. For each SPR supported,
+ * there is an associated bit position in the bit vector.Refer
+ * to definition of SprBitPositionList_t to determine bit position
+ * associated with a particular SPR.
+ */
+StopReturnCode_t
+p9_stop_save_cpureg_control( void* i_pImage, const uint64_t i_pir,
+ const uint32_t i_saveRegVector );
#ifdef __cplusplus
} // extern "C"
}; // namespace stopImageSection ends
diff --git a/include/skiboot.h b/include/skiboot.h
index 96d25b8..3003642 100644
--- a/include/skiboot.h
+++ b/include/skiboot.h
@@ -207,6 +207,7 @@ extern void early_uart_init(void);
extern void homer_init(void);
extern void slw_init(void);
extern void add_cpu_idle_state_properties(void);
+extern void add_cpu_self_save_properties(void);
extern void lpc_rtc_init(void);
/* flash support */
@@ -305,6 +306,9 @@ extern void xive_late_init(void);
/* SLW reinit function for switching core settings */
extern int64_t slw_reinit(uint64_t flags);
+/* Self save SPR before entering the stop state */
+extern int64_t opal_slw_self_save_reg(uint64_t cpu_pir, uint64_t sprn);
+
/* Patch SPR in SLW image */
extern int64_t opal_slw_set_reg(uint64_t cpu_pir, uint64_t sprn, uint64_t val);
diff --git a/include/ultravisor.h b/include/ultravisor.h
index d28cd4d..9852a1d 100644
--- a/include/ultravisor.h
+++ b/include/ultravisor.h
@@ -25,6 +25,8 @@
extern bool uv_present;
#define is_uv_present() uv_present
+extern uint64_t uv_base_addr;
+
extern int start_uv(uint64_t entry, struct uv_opal *uv_opal);
extern bool uv_add_mem_range(__be64 start, __be64 end);
extern void uv_preload_image(void);
diff --git a/libpore/p9_cpu_reg_restore_instruction.H b/libpore/p9_cpu_reg_restore_instruction.H
index dd4358a..27603b2 100644
--- a/libpore/p9_cpu_reg_restore_instruction.H
+++ b/libpore/p9_cpu_reg_restore_instruction.H
@@ -68,6 +68,7 @@ enum
MFSPR_CONST = 339,
BLR_INST = 0x4e800020,
MTSPR_BASE_OPCODE = 0x7c0003a6,
+ MFSPR_BASE_OPCODE = 0x7c0002a6,
ATTN_OPCODE = 0x00000200,
OPCODE_18 = 18,
SELF_SAVE_FUNC_ADD = 0x2300,
diff --git a/libpore/p9_stop_api.C b/libpore/p9_stop_api.C
index 33aaf78..d231d1e 100644
--- a/libpore/p9_stop_api.C
+++ b/libpore/p9_stop_api.C
@@ -54,26 +54,26 @@ namespace stopImageSection
const StopSprReg_t g_sprRegister[] =
{
- { P9_STOP_SPR_CIABR, true, 0 },
- { P9_STOP_SPR_DAWR, true, 1 },
- { P9_STOP_SPR_DAWRX, true, 2 },
- { P9_STOP_SPR_HSPRG0, true, 3 },
- { P9_STOP_SPR_LDBAR, true, 4, },
- { P9_STOP_SPR_LPCR, true, 5 },
- { P9_STOP_SPR_PSSCR, true, 6 },
- { P9_STOP_SPR_MSR, true, 7 },
- { P9_STOP_SPR_HRMOR, false, 20 },
- { P9_STOP_SPR_HID, false, 21 },
- { P9_STOP_SPR_HMEER, false, 22 },
- { P9_STOP_SPR_PMCR, false, 23 },
- { P9_STOP_SPR_PTCR, false, 24 },
- { P9_STOP_SPR_SMFCTRL, true, 28 },
- { P9_STOP_SPR_USPRG0, true, 29 },
- { P9_STOP_SPR_USPRG1, true, 30 },
- { P9_STOP_SPR_URMOR, false, 31 },
+ { P9_STOP_SPR_CIABR, true, 0 },
+ { P9_STOP_SPR_DAWR, true, 1 },
+ { P9_STOP_SPR_DAWRX, true, 2 },
+ { P9_STOP_SPR_HSPRG0, true, 3 },
+ { P9_STOP_SPR_LDBAR, true, 4, },
+ { P9_STOP_SPR_LPCR, true, 5 },
+ { P9_STOP_SPR_PSSCR, true, 6 },
+ { P9_STOP_SPR_MSR, true, 7 },
+ { P9_STOP_SPR_HRMOR, false, 255 },
+ { P9_STOP_SPR_HID, false, 21 },
+ { P9_STOP_SPR_HMEER, false, 22 },
+ { P9_STOP_SPR_PMCR, false, 23 },
+ { P9_STOP_SPR_PTCR, false, 24 },
+ { P9_STOP_SPR_SMFCTRL, true, 28 },
+ { P9_STOP_SPR_USPRG0, true, 29 },
+ { P9_STOP_SPR_USPRG1, true, 30 },
+ { P9_STOP_SPR_URMOR, false, 255 },
};
-const uint32_t MAX_SPR_SUPPORTED = 17;
+const uint32_t MAX_SPR_SUPPORTED = 17;
const uint32_t LEGACY_CORE_SCOM_SUPPORTED = 15;
const uint32_t LEGACY_QUAD_SCOM_SUPPORTED = 63;
@@ -255,7 +255,7 @@ STATIC uint32_t getOriInstruction( const uint16_t i_Rs, const uint16_t i_Ra,
*/
STATIC uint32_t genKeyForSprLookup( const CpuReg_t i_regId )
{
- return getOriInstruction( 0, 0, (uint16_t) i_regId );
+ return getOriInstruction( 24, 0, (uint16_t) i_regId );
}
//-----------------------------------------------------------------------------
@@ -330,7 +330,7 @@ STATIC uint32_t getMtsprInstruction( const uint16_t i_Rs, const uint16_t i_Spr )
*/
STATIC uint32_t getMfmsrInstruction( const uint16_t i_Rt )
{
- uint32_t mfmsrInstOpcode = ((OPCODE_31 << 26) | (i_Rt << 21) | (MFMSR_CONST));
+ uint32_t mfmsrInstOpcode = ((OPCODE_31 << 26) | (i_Rt << 21) | ((MFMSR_CONST)<< 1));
return SWIZZLE_4_BYTE(mfmsrInstOpcode);
}
@@ -361,8 +361,13 @@ STATIC uint32_t getRldicrInstruction( const uint16_t i_Ra, const uint16_t i_Rs,
STATIC uint32_t getMfsprInstruction( const uint16_t i_Rt, const uint16_t i_sprNum )
{
- uint32_t mfsprInstOpcode = 0;
- mfsprInstOpcode = (( OPCODE_31 << 26 ) | ( i_Rt << 21 ) | ( i_sprNum << 11 ) | ( MFSPR_CONST << 1 ));
+ uint32_t mfsprInstOpcode = 0;
+ uint32_t temp = (( i_sprNum & 0x03FF ) << 11);
+ mfsprInstOpcode = (uint8_t)i_Rt << 21;
+ mfsprInstOpcode |= (( temp & 0x0000F800 ) << 5);
+ mfsprInstOpcode |= (( temp & 0x001F0000 ) >> 5);
+ mfsprInstOpcode |= MFSPR_BASE_OPCODE;
+
return SWIZZLE_4_BYTE(mfsprInstOpcode);
}
@@ -615,14 +620,14 @@ STATIC StopReturnCode_t getSprRegIndexAdjustment( const uint32_t i_saveMaskPos,
do
{
- if( (( i_saveMaskPos >= SPR_BIT_POS_8 ) && ( i_saveMaskPos <= SPR_BIT_POS_19 )) ||
+ if( (( i_saveMaskPos >= SPR_BIT_POS_8 ) && ( i_saveMaskPos <= SPR_BIT_POS_20 )) ||
(( i_saveMaskPos >= SPR_BIT_POS_25 ) && ( i_saveMaskPos <= SPR_BIT_POS_27 )) )
{
l_rc = STOP_SAVE_SPR_BIT_POS_RESERVE;
break;
}
- if( (i_saveMaskPos > SPR_BIT_POS_19) && (i_saveMaskPos < SPR_BIT_POS_25 ) )
+ if( (i_saveMaskPos > SPR_BIT_POS_20) && (i_saveMaskPos < SPR_BIT_POS_25) )
{
*i_sprAdjIndex = 12;
}
@@ -1396,7 +1401,7 @@ STATIC StopReturnCode_t updateSelfSaveEntry( uint32_t* i_pSaveReg, uint16_t i_sp
//-----------------------------------------------------------------------------
-StopReturnCode_t p9_stop_save_cpureg_control( void* i_pImage,
+StopReturnCode_t p9_stop_save_cpureg_control( void* const i_pImage,
const uint64_t i_pir,
const uint32_t i_saveRegVector )
{
@@ -1411,6 +1416,7 @@ StopReturnCode_t p9_stop_save_cpureg_control( void* i_pImage,
uint32_t* l_pRestoreStart = NULL;
uint32_t* l_pSprSave = NULL;
void* l_pTempLoc = NULL;
+ uint32_t * l_pTempWord = NULL;
SmfHomerSection_t* l_pHomer = NULL;
uint8_t l_selfRestVer = 0;
@@ -1440,6 +1446,11 @@ StopReturnCode_t p9_stop_save_cpureg_control( void* i_pImage,
{
l_sprPos = g_sprRegister[l_sprIndex].iv_saveMaskPos;
+ if( l_sprPos > MAX_SPR_BIT_POS )
+ {
+ continue;
+ }
+
//Check if a given SPR needs to be self-saved each time on STOP entry
if( i_saveRegVector & ( TEST_BIT_PATTERN >> l_sprPos ) )
@@ -1493,6 +1504,19 @@ StopReturnCode_t p9_stop_save_cpureg_control( void* i_pImage,
//update specific instructions of self save region to enable saving for SPR
l_rc = updateSelfSaveEntry( l_pSprSave, g_sprRegister[l_sprIndex].iv_sprId );
+ if( l_rc )
+ {
+ MY_ERR( "Failed to update self save instructions for 0x%08x",
+ (uint32_t) g_sprRegister[l_sprIndex].iv_sprId );
+ }
+
+ if( l_pTempLoc )
+ {
+ l_pTempWord = (uint32_t *)l_pTempLoc;
+ l_pTempWord++;
+ *l_pTempWord = getXorInstruction( 0, 0, 0 );
+ }
+
}// end if( i_saveRegVector..)
}// end for
}
diff --git a/libpore/p9_stop_api.H b/libpore/p9_stop_api.H
index 17caedb..ef0d9d1 100644
--- a/libpore/p9_stop_api.H
+++ b/libpore/p9_stop_api.H
@@ -148,7 +148,6 @@ typedef enum
BIT_POS_LPCR = 5,
BIT_POS_PSSCR = 6,
BIT_POS_MSR = 7,
- BIT_POS_HRMOR = 20,
BIT_POS_HID = 21,
BIT_POS_HMEER = 22,
BIT_POS_PMCR = 23,
@@ -156,7 +155,6 @@ typedef enum
BIT_POS_SMFCTRL = 28,
BIT_POS_USPRG0 = 29,
BIT_POS_USPRG1 = 30,
- BIT_POS_URMOR = 31,
} SprBitPositionList_t;
diff --git a/libpore/p9_stop_data_struct.H b/libpore/p9_stop_data_struct.H
index 1e9721e..4e73aab 100644
--- a/libpore/p9_stop_data_struct.H
+++ b/libpore/p9_stop_data_struct.H
@@ -67,9 +67,9 @@ enum
SIZE_PER_SPR_RESTORE_INST = ((4 * sizeof(uint8_t)) / sizeof(uint32_t)),
MAX_THREAD_LEVEL_SPRS = 11,
MAX_CORE_LEVEL_SPRS = 6,
- MAX_SPR_BIT_POS = 31,
+ MAX_SPR_BIT_POS = 30,
SPR_BIT_POS_8 = 8,
- SPR_BIT_POS_19 = 19,
+ SPR_BIT_POS_20 = 20,
SPR_BIT_POS_25 = 25,
SPR_BIT_POS_27 = 27,
};
diff --git a/libpore/p9_stop_util.H b/libpore/p9_stop_util.H
index 3266fde..8f504ba 100644
--- a/libpore/p9_stop_util.H
+++ b/libpore/p9_stop_util.H
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2016,2017 */
+/* Contributors Listed Below - COPYRIGHT 2016,2018,2019 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -95,7 +95,10 @@ typedef struct
uint64_t cpmrMagicWord;
uint32_t buildDate;
uint32_t version;
- uint8_t reserve1[7];
+ uint8_t reserve1[4];
+ uint8_t selfRestoreVer;
+ uint8_t stopApiVer;
+ uint8_t urmorFix;
uint8_t fusedModeStatus;
uint32_t cmeImgOffset;
uint32_t cmeImgLength;