diff -up skiboot-5.9/core/hostservices.c.me skiboot-5.9/core/hostservices.c --- skiboot-5.9/core/hostservices.c.me 2017-10-31 05:29:28.000000000 +0100 +++ skiboot-5.9/core/hostservices.c 2018-01-22 11:42:23.462547265 +0100 @@ -697,34 +697,49 @@ static int hservice_clr_special_wakeup(s 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" @@ -738,7 +753,7 @@ static int hservice_wakeup(uint32_t i_co /* 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"); @@ -746,7 +761,7 @@ static int hservice_wakeup(uint32_t i_co 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; diff -up skiboot-5.9/external/opal-prd/opal-prd.c.me skiboot-5.9/external/opal-prd/opal-prd.c --- skiboot-5.9/external/opal-prd/opal-prd.c.me 2017-10-31 05:29:28.000000000 +0100 +++ skiboot-5.9/external/opal-prd/opal-prd.c 2018-01-22 11:42:23.463547227 +0100 @@ -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) @@ -521,6 +524,24 @@ int hservice_i2c_write(uint64_t i_master 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"); @@ -1170,6 +1191,52 @@ static void print_ranges(struct opal_prd } } +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; @@ -1290,6 +1357,10 @@ static int prd_init(struct opal_prd_ctx return -1; } + rc = chip_init(); + if (rc) + pr_log(LOG_ERR, "FW: Failed to initialize chip IDs"); + return 0; } @@ -1433,6 +1504,41 @@ static int handle_msg_sbe_passthrough(st 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; @@ -1453,6 +1559,9 @@ static int handle_prd_msg(struct opal_pr 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); @@ -1985,6 +2094,9 @@ static int run_prd_daemon(struct opal_pr hinterface.pnor_write = NULL; } + if (!is_fsp_system()) + hinterface.wakeup = NULL; + ipmi_init(ctx); pr_debug("HBRT: calling hservices_init"); diff -up skiboot-5.9/external/opal-prd/thunk.S.me skiboot-5.9/external/opal-prd/thunk.S --- skiboot-5.9/external/opal-prd/thunk.S.me 2017-10-31 05:29:28.000000000 +0100 +++ skiboot-5.9/external/opal-prd/thunk.S 2018-01-22 11:42:23.463547227 +0100 @@ -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) diff -up skiboot-5.9/hw/occ.c.me skiboot-5.9/hw/occ.c --- skiboot-5.9/hw/occ.c.me 2017-10-31 05:29:28.000000000 +0100 +++ skiboot-5.9/hw/occ.c 2018-01-22 11:42:23.463547227 +0100 @@ -1837,6 +1837,44 @@ 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; + + 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; @@ -1877,7 +1915,18 @@ static void occ_do_reset(u8 scope, u32 d * 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) { diff -up skiboot-5.9/hw/prd.c.me skiboot-5.9/hw/prd.c --- skiboot-5.9/hw/prd.c.me 2017-10-31 05:29:28.000000000 +0100 +++ skiboot-5.9/hw/prd.c 2018-01-22 11:42:23.464547189 +0100 @@ -29,6 +29,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]; @@ -114,6 +115,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); @@ -188,6 +193,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; } /* @@ -274,6 +282,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); @@ -418,6 +431,14 @@ static int64_t opal_prd_msg(struct opal_ 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; } diff -up skiboot-5.9/include/hostservices.h.me skiboot-5.9/include/hostservices.h --- skiboot-5.9/include/hostservices.h.me 2018-01-22 11:42:23.464547189 +0100 +++ skiboot-5.9/include/hostservices.h 2018-01-22 11:42:57.522259222 +0100 @@ -38,5 +38,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_wakeup(uint32_t i_core, uint32_t i_mode); +int fsp_occ_reset_status(u64 chipid, s64 status); #endif /* __HOSTSERVICES_H */ diff -up skiboot-5.9/include/opal-api.h.me skiboot-5.9/include/opal-api.h --- skiboot-5.9/include/opal-api.h.me 2017-10-31 05:29:28.000000000 +0100 +++ skiboot-5.9/include/opal-api.h 2018-01-22 11:42:23.465547151 +0100 @@ -1054,6 +1054,9 @@ 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_FSP_OCC_RESET, /* HBRT <-- OPAL */ + OPAL_PRD_MSG_TYPE_FSP_OCC_RESET_STATUS, /* HBRT --> OPAL */ + OPAL_PRD_MSG_TYPE_CORE_SPECIAL_WAKEUP, /* HBRT --> OPAL */ }; struct opal_prd_msg_header { @@ -1101,6 +1104,14 @@ struct opal_prd_msg { struct { __be64 chip; } sbe_passthrough; + struct { + __be64 chip; + __be64 status; /* 0 SUCCESS */ + } fsp_occ_reset_status; + struct { + __be32 core; + __be32 mode; + } spl_wakeup; }; }; diff -up skiboot-5.9/include/skiboot.h.me skiboot-5.9/include/skiboot.h --- skiboot-5.9/include/skiboot.h.me 2017-10-31 05:29:28.000000000 +0100 +++ skiboot-5.9/include/skiboot.h 2018-01-22 11:42:23.465547151 +0100 @@ -293,6 +293,7 @@ extern void prd_occ_reset(uint32_t proc) extern void prd_sbe_passthrough(uint32_t proc); extern void prd_init(void); extern void prd_register_reserved_memory(void); +extern void prd_fsp_occ_reset(uint32_t proc); /* Flatten device-tree */ extern void *create_dtb(const struct dt_node *root, bool exclusive); diff -up skiboot-5.9/core/direct-controls.c.me skiboot-5.9/core/direct-controls.c --- skiboot-5.9/core/direct-controls.c.me 2017-10-31 00:29:28.000000000 -0400 +++ skiboot-5.9/core/direct-controls.c 2018-01-22 07:12:07.642733620 -0500 @@ -220,7 +220,7 @@ static int p9_sreset_thread(struct cpu_t return 0; } -static int dctl_set_special_wakeup(struct cpu_thread *t) +int dctl_set_special_wakeup(struct cpu_thread *t) { struct cpu_thread *c = t->primary; int rc = OPAL_SUCCESS; @@ -238,7 +238,7 @@ static int dctl_set_special_wakeup(struc return rc; } -static int dctl_clear_special_wakeup(struct cpu_thread *t) +int dctl_clear_special_wakeup(struct cpu_thread *t) { struct cpu_thread *c = t->primary; int rc = OPAL_SUCCESS; diff -up skiboot-5.9/hw/prd.c.me skiboot-5.9/hw/prd.c --- skiboot-5.9/hw/prd.c.me 2018-01-22 07:14:59.985852136 -0500 +++ skiboot-5.9/hw/prd.c 2018-01-22 07:15:11.146054087 -0500 @@ -23,6 +23,7 @@ #include #include #include +#include enum events { EVENT_ATTN = 1 << 0, diff -up skiboot-5.9/include/cpu.h.me skiboot-5.9/include/cpu.h --- skiboot-5.9/include/cpu.h.me 2017-10-31 00:29:28.000000000 -0400 +++ skiboot-5.9/include/cpu.h 2018-01-22 07:12:07.642733620 -0500 @@ -284,4 +284,7 @@ extern void cpu_idle_delay(unsigned long extern void cpu_set_radix_mode(void); extern void cpu_fast_reboot_complete(void); +int dctl_set_special_wakeup(struct cpu_thread *t); +int dctl_clear_special_wakeup(struct cpu_thread *t); + #endif /* __CPU_H */