@@ -721,17 +721,23 @@ static int hservice_wakeup(uint32_t i_core, uint32_t i_mode)
struct cpu_thread *cpu;
int rc = OPAL_SUCCESS;
- /*
- * Mask out the top nibble of i_core since it may contain
- * 0x4 (which we use for XSCOM targeting)
- */
- i_core &= 0x0fffffff;
+ switch (proc_gen) {
+ case proc_gen_p8:
+ i_core &= SPR_PIR_P8_MASK;
+ i_core <<= 3;
+ break;
+ case proc_gen_p9:
+ i_core &= SPR_PIR_P9_MASK;
+ i_core <<= 2;
+ break;
+ default:
+ return OPAL_UNSUPPORTED;
+ }
/* What do we need to do ? */
switch(i_mode) {
case 0: /* Assert special wakeup */
- /* XXX Assume P8 */
- cpu = find_cpu_by_pir(i_core << 3);
+ cpu = find_cpu_by_pir(i_core);
if (!cpu)
return OPAL_PARAMETER;
prlog(PR_DEBUG, "HBRT: Special wakeup assert for core 0x%x,"
@@ -742,8 +748,7 @@ static int hservice_wakeup(uint32_t i_core, uint32_t i_mode)
cpu->hbrt_spec_wakeup++;
return rc;
case 1: /* Deassert special wakeup */
- /* XXX Assume P8 */
- cpu = find_cpu_by_pir(i_core << 3);
+ cpu = find_cpu_by_pir(i_core);
if (!cpu)
return OPAL_PARAMETER;
prlog(PR_DEBUG, "HBRT: Special wakeup release for core"
@@ -774,6 +779,11 @@ static int hservice_wakeup(uint32_t i_core, uint32_t i_mode)
}
}
+int core_special_wakeup(u32 core, u32 mode)
+{
+ return hservice_wakeup(core, mode);
+}
+
static struct host_interfaces hinterface = {
.interface_version = HOSTBOOT_RUNTIME_INTERFACE_VERSION,
.puts = hservice_puts,
@@ -506,6 +506,25 @@ int hservice_i2c_write(uint64_t i_master, uint16_t i_devAddr,
i_offset, i_length, i_data);
}
+int hservice_wakeup(u32 core, u32 mode)
+{
+ int rc;
+ struct opal_prd_msg msg;
+
+ msg.hdr.type = OPAL_PRD_MSG_TYPE_CORE_SPECIAL_WAKEUP;
+ msg.hdr.size = htobe16(sizeof(msg));
+ msg.spl_wakeup.core = htobe32(core);
+ msg.spl_wakeup.mode = htobe32(mode);
+
+ rc = write(ctx->fd, &msg, sizeof(msg));
+ if (rc != sizeof(msg)) {
+ pr_log(LOG_ERR, "FW: failed for core %x : %m\n", core);
+ return rc;
+ }
+
+ return 0;
+}
+
static void ipmi_init(struct opal_prd_ctx *ctx)
{
insert_module("ipmi_devintf");
@@ -1353,9 +1372,24 @@ static int pm_complex_reset(uint64_t chip)
return rc;
}
+static bool is_fsp(void)
+{
+ char *path;
+ int rc;
+
+ rc = asprintf(&path, "%s/fsps", devicetree_base);
+ if (rc < 0) {
+ pr_log(LOG_ERR, "PRD: error creating '/fsps' path %m");
+ return false;
+ }
+
+ return access(path, F_OK) ? false : true;
+}
+
static int handle_msg_occ_reset(struct opal_prd_ctx *ctx,
struct opal_prd_msg *msg)
{
+ struct opal_prd_msg omsg;
uint32_t proc;
int rc;
@@ -1365,7 +1399,22 @@ static int handle_msg_occ_reset(struct opal_prd_ctx *ctx,
rc = pm_complex_reset(proc);
- return rc;
+ if (!is_fsp())
+ return rc;
+
+ /* Send only for zz */
+ omsg.hdr.type = OPAL_PRD_MSG_TYPE_OCC_RESET_STATUS;
+ omsg.hdr.size = htobe16(sizeof(omsg));
+ omsg.occ_reset_status.chip = htobe64(proc);
+ omsg.occ_reset_status.status = htobe64(rc);
+
+ rc = write(ctx->fd, &omsg, sizeof(omsg));
+ if (rc != sizeof(omsg)) {
+ pr_log(LOG_ERR, "FW: Failed to send OCC_RESET status message: %m");
+ return rc;
+ }
+
+ return 0;
}
static int handle_msg_firmware_notify(struct opal_prd_ctx *ctx,
@@ -1961,6 +2010,9 @@ static int run_prd_daemon(struct opal_prd_ctx *ctx)
hinterface.pnor_write = NULL;
}
+ if (!is_fsp())
+ hinterface.wakeup = NULL;
+
ipmi_init(ctx);
pr_debug("HBRT: calling hservices_init");
@@ -183,7 +183,7 @@ hinterface:
DISABLED_THUNK(hservice_lid_load)
DISABLED_THUNK(hservice_lid_unload)
CALLBACK_THUNK(hservice_get_reserved_mem)
- DISABLED_THUNK(hservice_wakeup)
+ CALLBACK_THUNK(hservice_wakeup)
CALLBACK_THUNK(hservice_nanosleep)
DISABLED_THUNK(hservice_report_occ_failure)
CALLBACK_THUNK(hservice_clock_gettime)
@@ -1837,6 +1837,40 @@ out:
return rc;
}
+static u32 last_seq_id;
+
+int fsp_occ_reset_status(u64 chipid, s64 status)
+{
+ struct fsp_msg *stat;
+ int rc = OPAL_NO_MEM;
+ int status_word = 0;
+
+ if (status) {
+ struct proc_chip *chip = get_chip(chipid);
+
+ if (!chip)
+ return OPAL_PARAMETER;
+
+ status_word = 0xfe00 | (chip->pcid & 0xff);
+ log_simple_error(&e_info(OPAL_RC_OCC_RESET),
+ "OCC: Error %d in OCC reset of chip %lld\n", rc,
+ chipid);
+ }
+
+ stat = fsp_mkmsg(FSP_CMD_RESET_OCC_STAT, 2, status_word, last_seq_id);
+ if (!stat)
+ return rc;
+
+ rc = fsp_queue_msg(stat, fsp_freemsg);
+ if (rc) {
+ fsp_freemsg(stat);
+ log_simple_error(&e_info(OPAL_RC_OCC_RESET),
+ "OCC: Error %d queueing FSP OCC RESET STATUS message\n",
+ rc);
+ }
+ return rc;
+}
+
static void occ_do_reset(u8 scope, u32 dbob_id, u32 seq_id)
{
struct fsp_msg *rsp, *stat;
@@ -1877,7 +1911,18 @@ static void occ_do_reset(u8 scope, u32 dbob_id, u32 seq_id)
* FSP will request OCC to left in stopped state.
*/
- rc = host_services_occ_stop();
+ switch (proc_gen) {
+ case proc_gen_p8:
+ rc = host_services_occ_stop();
+ break;
+ case proc_gen_p9:
+ last_seq_id = seq_id;
+ for_each_chip(chip)
+ prd_occ_reset(chip->id);
+ return;
+ default:
+ return;
+ }
/* Handle fallback to preload */
if (rc == -ENOENT && chip->homer_base) {
@@ -418,6 +418,14 @@ static int64_t opal_prd_msg(struct opal_prd_msg *msg)
case OPAL_PRD_MSG_TYPE_FIRMWARE_REQUEST:
rc = prd_msg_handle_firmware_req(msg);
break;
+ case OPAL_PRD_MSG_TYPE_OCC_RESET_STATUS:
+ rc = fsp_occ_reset_status(msg->occ_reset_status.chip,
+ msg->occ_reset_status.status);
+ break;
+ case OPAL_PRD_MSG_TYPE_CORE_SPECIAL_WAKEUP:
+ rc = core_special_wakeup(msg->spl_wakeup.core,
+ msg->spl_wakeup.mode);
+ break;
default:
rc = OPAL_UNSUPPORTED;
}
@@ -1052,6 +1052,8 @@ enum opal_prd_msg_type {
OPAL_PRD_MSG_TYPE_FIRMWARE_RESPONSE, /* HBRT <-- OPAL */
OPAL_PRD_MSG_TYPE_FIRMWARE_NOTIFY, /* HBRT <-- OPAL */
OPAL_PRD_MSG_TYPE_SBE_PASSTHROUGH, /* HBRT <-- OPAL */
+ OPAL_PRD_MSG_TYPE_OCC_RESET_STATUS, /* HBRT --> OPAL */
+ OPAL_PRD_MSG_TYPE_CORE_SPECIAL_WAKEUP, /* HBRT --> OPAL */
};
struct opal_prd_msg_header {
@@ -1099,6 +1101,14 @@ struct opal_prd_msg {
struct {
__be64 chip;
} sbe_passthrough;
+ struct {
+ __be64 chip;
+ __be64 status; /* 0 SUCCESS */
+ } occ_reset_status;
+ struct {
+ __be32 core;
+ __be32 mode;
+ } spl_wakeup;
};
};
@@ -320,4 +320,6 @@ extern int occ_sensor_group_clear(u32 group_hndl, int token);
extern void occ_add_sensor_groups(struct dt_node *sg, u32 *phandles,
int nr_phandles, int chipid);
+extern int fsp_occ_reset_status(u64 chipid, s64 status);
+extern int core_special_wakeup(u32 core, u32 mode);
#endif /* __SKIBOOT_H */
This patch handles OCC_RESET runtime events in host opal-prd and also provides support for calling 'hostinterface->wakeup()' which is required for doing the reset operation. Signed-off-by: Shilpasri G Bhat <shilpa.bhat@linux.vnet.ibm.com> --- Changes from V2: - Disable hservice_wakeup() on BMC - Check the status and send a single FSP message core/hostservices.c | 28 +++++++++++++++-------- external/opal-prd/opal-prd.c | 54 +++++++++++++++++++++++++++++++++++++++++++- external/opal-prd/thunk.S | 2 +- hw/occ.c | 47 +++++++++++++++++++++++++++++++++++++- hw/prd.c | 8 +++++++ include/opal-api.h | 10 ++++++++ include/skiboot.h | 2 ++ 7 files changed, 139 insertions(+), 12 deletions(-)