Skip to content

Commit

Permalink
opal-prd: Add support for runtime OCC reset in ZZ
Browse files Browse the repository at this point in the history
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>
Acked-by: Jeremy Kerr <jk@ozlabs.org>
Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
  • Loading branch information
shilpasri authored and stewartsmith committed Dec 15, 2017
1 parent 5d847a1 commit 4999930
Show file tree
Hide file tree
Showing 8 changed files with 226 additions and 15 deletions.
41 changes: 28 additions & 13 deletions core/hostservices.c
Expand Up @@ -697,34 +697,49 @@ static int hservice_clr_special_wakeup(struct cpu_thread *cpu)
return 0;
}

static int hservice_wakeup(uint32_t i_core, uint32_t i_mode)
int hservice_wakeup(uint32_t i_core, uint32_t i_mode)
{
int (*set_wakeup)(struct cpu_thread *cpu);
int (*clear_wakeup)(struct cpu_thread *cpu);
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:
/*
* Mask out the top nibble of i_core since it may contain
* 0x4 (which we use for XSCOM targeting)
*/
i_core &= 0x0fffffff;
i_core <<= 3;
set_wakeup = hservice_set_special_wakeup;
clear_wakeup = hservice_clr_special_wakeup;
break;
case proc_gen_p9:
i_core &= SPR_PIR_P9_MASK;
i_core <<= 2;
set_wakeup = dctl_set_special_wakeup;
clear_wakeup = dctl_clear_special_wakeup;
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,"
" count=%d\n", i_core, cpu->hbrt_spec_wakeup);
if (cpu->hbrt_spec_wakeup == 0)
rc = hservice_set_special_wakeup(cpu);
rc = set_wakeup(cpu);
if (rc == 0)
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"
Expand All @@ -738,15 +753,15 @@ static int hservice_wakeup(uint32_t i_core, uint32_t i_mode)
/* What to do with count on errors ? */
cpu->hbrt_spec_wakeup--;
if (cpu->hbrt_spec_wakeup == 0)
rc = hservice_clr_special_wakeup(cpu);
rc = clear_wakeup(cpu);
return rc;
case 2: /* Clear all special wakeups */
prlog(PR_DEBUG, "HBRT: Special wakeup release for all cores\n");
for_each_cpu(cpu) {
if (cpu->hbrt_spec_wakeup) {
cpu->hbrt_spec_wakeup = 0;
/* What to do on errors ? */
hservice_clr_special_wakeup(cpu);
clear_wakeup(cpu);
}
}
return OPAL_SUCCESS;
Expand Down
112 changes: 112 additions & 0 deletions external/opal-prd/opal-prd.c
Expand Up @@ -163,6 +163,9 @@ struct func_desc {
void *toc;
} hbrt_entry;

static int nr_chips;
static u64 chips[256];

static int read_prd_msg(struct opal_prd_ctx *ctx);

static struct prd_range *find_range(const char *name, uint32_t instance)
Expand Down Expand Up @@ -524,6 +527,24 @@ 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)
{
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);

if (write(ctx->fd, &msg, sizeof(msg)) != sizeof(msg)) {
pr_log(LOG_ERR, "FW: Failed to send CORE_SPECIAL_WAKEUP msg %x : %m\n",
core);
return -1;
}

return 0;
}

static void ipmi_init(struct opal_prd_ctx *ctx)
{
insert_module("ipmi_devintf");
Expand Down Expand Up @@ -1173,6 +1194,52 @@ static void print_ranges(struct opal_prd_ctx *ctx)
}
}

static int chip_init(void)
{
struct dirent *dirent;
char *path;
DIR *dir;
__be32 *chipid;
void *buf;
int rc, len, i;

dir = opendir(devicetree_base);
if (!dir) {
pr_log(LOG_ERR, "FW: Can't open %s", devicetree_base);
return -1;
}

for (;;) {
dirent = readdir(dir);
if (!dirent)
break;

if (strncmp("xscom", dirent->d_name, 5))
continue;

rc = asprintf(&path, "%s/%s/ibm,chip-id", devicetree_base,
dirent->d_name);
if (rc < 0) {
pr_log(LOG_ERR, "FW: Failed to create chip-id path");
return -1;
}

rc = open_and_read(path, &buf, &len);
if (rc) {
pr_log(LOG_ERR, "FW; Failed to read chipid");
return -1;
}
chipid = buf;
chips[nr_chips++] = be32toh(*chipid);
}

pr_log(LOG_DEBUG, "FW: Chip init");
for (i = 0; i < nr_chips; i++)
pr_log(LOG_DEBUG, "FW: Chip 0x%lx", chips[i]);

return 0;
}

static int prd_init_ranges(struct opal_prd_ctx *ctx)
{
struct dirent *dirent;
Expand Down Expand Up @@ -1293,6 +1360,10 @@ static int prd_init(struct opal_prd_ctx *ctx)
return -1;
}

rc = chip_init();
if (rc)
pr_log(LOG_ERR, "FW: Failed to initialize chip IDs");

return 0;
}

Expand Down Expand Up @@ -1436,6 +1507,41 @@ static int handle_msg_sbe_passthrough(struct opal_prd_ctx *ctx,
return rc;
}

static int handle_msg_fsp_occ_reset(struct opal_prd_msg *msg)
{
struct opal_prd_msg omsg;
int rc = -1, i;

pr_debug("FW: FSP requested OCC reset");

if (!hservice_runtime->reset_pm_complex) {
pr_log_nocall("reset_pm_complex");
return rc;
}

for (i = 0; i < nr_chips; i++) {
pr_debug("PM: calling pm_complex_reset(0x%lx)", chips[i]);
rc = call_reset_pm_complex(chips[i]);
if (rc) {
pr_log(LOG_ERR, "PM: Failed pm_complex_reset(0x%lx) %m",
chips[i]);
break;
}
}

omsg.hdr.type = OPAL_PRD_MSG_TYPE_FSP_OCC_RESET_STATUS;
omsg.hdr.size = htobe16(sizeof(omsg));
omsg.fsp_occ_reset_status.chip = msg->occ_reset.chip;
omsg.fsp_occ_reset_status.status = htobe64(rc);

if (write(ctx->fd, &omsg, sizeof(omsg)) != sizeof(omsg)) {
pr_log(LOG_ERR, "FW: Failed to send FSP_OCC_RESET_STATUS msg: %m");
return -1;
}

return rc;
}

static int handle_prd_msg(struct opal_prd_ctx *ctx, struct opal_prd_msg *msg)
{
int rc = -1;
Expand All @@ -1456,6 +1562,9 @@ static int handle_prd_msg(struct opal_prd_ctx *ctx, struct opal_prd_msg *msg)
case OPAL_PRD_MSG_TYPE_SBE_PASSTHROUGH:
rc = handle_msg_sbe_passthrough(ctx, msg);
break;
case OPAL_PRD_MSG_TYPE_FSP_OCC_RESET:
rc = handle_msg_fsp_occ_reset(msg);
break;
default:
pr_log(LOG_WARNING, "Invalid incoming message type 0x%x",
msg->hdr.type);
Expand Down Expand Up @@ -1988,6 +2097,9 @@ static int run_prd_daemon(struct opal_prd_ctx *ctx)
hinterface.pnor_write = NULL;
}

if (!is_fsp_system())
hinterface.wakeup = NULL;

ipmi_init(ctx);

pr_debug("HBRT: calling hservices_init");
Expand Down
2 changes: 1 addition & 1 deletion external/opal-prd/thunk.S
Expand Up @@ -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)
Expand Down
51 changes: 50 additions & 1 deletion hw/occ.c
Expand Up @@ -1843,6 +1843,44 @@ int occ_msg_queue_occ_reset(void)
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;

prlog(PR_INFO, "HBRT: OCC stop() completed with %lld\n", status);

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 %lld in OCC reset of chip %lld\n",
status, chipid);
} else {
occ_msg_queue_occ_reset();
}

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;
Expand Down Expand Up @@ -1883,7 +1921,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;
chip = next_chip(NULL);
prd_fsp_occ_reset(chip->id);
return;
default:
return;
}

/* Handle fallback to preload */
if (rc == -ENOENT && chip->homer_base) {
Expand Down
21 changes: 21 additions & 0 deletions hw/prd.c
Expand Up @@ -30,6 +30,7 @@ enum events {
EVENT_OCC_ERROR = 1 << 1,
EVENT_OCC_RESET = 1 << 2,
EVENT_SBE_PASSTHROUGH = 1 << 3,
EVENT_FSP_OCC_RESET = 1 << 4,
};

static uint8_t events[MAX_CHIPS];
Expand Down Expand Up @@ -115,6 +116,10 @@ static void prd_msg_consumed(void *data)
proc = msg->sbe_passthrough.chip;
event = EVENT_SBE_PASSTHROUGH;
break;
case OPAL_PRD_MSG_TYPE_FSP_OCC_RESET:
proc = msg->occ_reset.chip;
event = EVENT_FSP_OCC_RESET;
break;
default:
prlog(PR_ERR, "PRD: invalid msg consumed, type: 0x%x\n",
msg->hdr.type);
Expand Down Expand Up @@ -189,6 +194,9 @@ static void send_next_pending_event(void)
} else if (event & EVENT_SBE_PASSTHROUGH) {
prd_msg->hdr.type = OPAL_PRD_MSG_TYPE_SBE_PASSTHROUGH;
prd_msg->sbe_passthrough.chip = proc;
} else if (event & EVENT_FSP_OCC_RESET) {
prd_msg->hdr.type = OPAL_PRD_MSG_TYPE_FSP_OCC_RESET;
prd_msg->occ_reset.chip = proc;
}

/*
Expand Down Expand Up @@ -275,6 +283,11 @@ void prd_occ_reset(uint32_t proc)
prd_event(proc, EVENT_OCC_RESET);
}

void prd_fsp_occ_reset(uint32_t proc)
{
prd_event(proc, EVENT_FSP_OCC_RESET);
}

void prd_sbe_passthrough(uint32_t proc)
{
prd_event(proc, EVENT_SBE_PASSTHROUGH);
Expand Down Expand Up @@ -431,6 +444,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_FSP_OCC_RESET_STATUS:
rc = fsp_occ_reset_status(msg->fsp_occ_reset_status.chip,
msg->fsp_occ_reset_status.status);
break;
case OPAL_PRD_MSG_TYPE_CORE_SPECIAL_WAKEUP:
rc = hservice_wakeup(msg->spl_wakeup.core,
msg->spl_wakeup.mode);
break;
default:
rc = OPAL_UNSUPPORTED;
}
Expand Down
2 changes: 2 additions & 0 deletions include/hostservices.h
Expand Up @@ -39,5 +39,7 @@ void host_services_occ_base_setup(void);
int find_master_and_slave_occ(uint64_t **master, uint64_t **slave,
int *nr_masters, int *nr_slaves);
int hservice_send_error_log(uint32_t plid, uint32_t dsize, void *data);
int hservice_wakeup(uint32_t i_core, uint32_t i_mode);
int fsp_occ_reset_status(u64 chipid, s64 status);

#endif /* __HOSTSERVICES_H */

0 comments on commit 4999930

Please sign in to comment.