diff options
author | Pratik Rajesh Sampat <psampat@linux.ibm.com> | 2019-11-26 20:27:19 +0530 |
---|---|---|
committer | Ram Pai <linuxram@us.ibm.com> | 2020-11-03 12:52:37 -0500 |
commit | adb88829e5d69d6e7105a5f68f6e8009eff208ff (patch) | |
tree | b52989126dec3e4eaf8d47dbdfc1a9c09838f5ef | |
parent | d85f89355e0bbcb5875dc2ccdcdb7fe3ccf5f701 (diff) | |
download | skiboot-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.c | 6 | ||||
-rw-r--r-- | doc/opal-api/opal-slw-self-save-reg-176.rst | 33 | ||||
-rw-r--r-- | hw/slw.c | 425 | ||||
-rw-r--r-- | hw/ultravisor.c | 2 | ||||
-rw-r--r-- | include/opal-api.h | 3 | ||||
-rw-r--r-- | include/p9_stop_api.H | 21 | ||||
-rw-r--r-- | include/skiboot.h | 4 | ||||
-rw-r--r-- | include/ultravisor.h | 2 | ||||
-rw-r--r-- | libpore/p9_cpu_reg_restore_instruction.H | 1 | ||||
-rw-r--r-- | libpore/p9_stop_api.C | 74 | ||||
-rw-r--r-- | libpore/p9_stop_api.H | 2 | ||||
-rw-r--r-- | libpore/p9_stop_data_struct.H | 4 | ||||
-rw-r--r-- | libpore/p9_stop_util.H | 7 |
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 @@ -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; |