diff options
author | Nicholas Piggin <npiggin@gmail.com> | 2018-05-03 18:38:08 +1000 |
---|---|---|
committer | Stewart Smith <stewart@linux.ibm.com> | 2018-05-06 10:27:37 -0500 |
commit | 5a1463d17d4b7420eba53be0f8a2fb3235dbaeff (patch) | |
tree | d86f0fd22dd1acd79c929cb93441632bbed4394c | |
parent | 7dcd66655835fb9985686dad1393285bb75a0876 (diff) | |
download | skiboot-5a1463d17d4b7420eba53be0f8a2fb3235dbaeff.zip skiboot-5a1463d17d4b7420eba53be0f8a2fb3235dbaeff.tar.gz skiboot-5a1463d17d4b7420eba53be0f8a2fb3235dbaeff.tar.bz2 |
core/direct-controls: fix p9_cont_thread for stopped/inactive threads
Firstly, p9_cont_thread should check that the thread actually was
quiesced before it tries to resume it. Anything could happen if we
try this from an arbitrary thread state.
Then when resuming a quiesced thread that is inactive or stopped (in
a stop idle state), we must not send a core_start direct control,
clear_maint must be used in these cases.
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Signed-off-by: Stewart Smith <stewart@linux.ibm.com>
-rw-r--r-- | core/direct-controls.c | 87 |
1 files changed, 70 insertions, 17 deletions
diff --git a/core/direct-controls.c b/core/direct-controls.c index c7b9c9b..4511a11 100644 --- a/core/direct-controls.c +++ b/core/direct-controls.c @@ -273,10 +273,14 @@ static int p8_sreset_thread(struct cpu_thread *cpu) #define P9_QUIESCE_POLL_INTERVAL 100 #define P9_QUIESCE_TIMEOUT 100000 +#define P9_CORE_THREAD_STATE 0x10ab3 +#define P9_THREAD_INFO 0x10a9b + #define P9_EC_DIRECT_CONTROLS 0x10a9c #define P9_THREAD_STOP(t) PPC_BIT(7 + 8*(t)) #define P9_THREAD_CONT(t) PPC_BIT(6 + 8*(t)) #define P9_THREAD_SRESET(t) PPC_BIT(4 + 8*(t)) +#define P9_THREAD_CLEAR_MAINT(t) PPC_BIT(3 + 8*(t)) #define P9_THREAD_PWR(t) PPC_BIT(32 + 8*(t)) /* EC_PPM_SPECIAL_WKUP_HYP */ @@ -412,6 +416,72 @@ static int p9_thread_quiesced(struct cpu_thread *cpu) return 0; } +static int p9_cont_thread(struct cpu_thread *cpu) +{ + uint32_t chip_id = pir_to_chip_id(cpu->pir); + uint32_t core_id = pir_to_core_id(cpu->pir); + uint32_t thread_id = pir_to_thread_id(cpu->pir); + uint32_t cts_addr; + uint32_t ti_addr; + uint32_t dctl_addr; + uint64_t core_thread_state; + uint64_t thread_info; + bool active, stop; + int rc; + + rc = p9_thread_quiesced(cpu); + if (rc < 0) + return rc; + if (!rc) { + prlog(PR_ERR, "Could not cont thread %u:%u:%u:" + " Thread is not quiesced.\n", + chip_id, core_id, thread_id); + return OPAL_BUSY; + } + + cts_addr = XSCOM_ADDR_P9_EC(core_id, P9_CORE_THREAD_STATE); + ti_addr = XSCOM_ADDR_P9_EC(core_id, P9_THREAD_INFO); + dctl_addr = XSCOM_ADDR_P9_EC(core_id, P9_EC_DIRECT_CONTROLS); + + if (xscom_read(chip_id, cts_addr, &core_thread_state)) { + prlog(PR_ERR, "Could not resume thread %u:%u:%u:" + " Unable to read CORE_THREAD_STATE.\n", + chip_id, core_id, thread_id); + return OPAL_HARDWARE; + } + if (core_thread_state & PPC_BIT(56 + thread_id)) + stop = true; + else + stop = false; + + if (xscom_read(chip_id, ti_addr, &thread_info)) { + prlog(PR_ERR, "Could not resume thread %u:%u:%u:" + " Unable to read THREAD_INFO.\n", + chip_id, core_id, thread_id); + return OPAL_HARDWARE; + } + if (thread_info & PPC_BIT(thread_id)) + active = true; + else + active = false; + + if (!active || stop) { + if (xscom_write(chip_id, dctl_addr, P9_THREAD_CLEAR_MAINT(thread_id))) { + prlog(PR_ERR, "Could not resume thread %u:%u:%u:" + " Unable to write EC_DIRECT_CONTROLS.\n", + chip_id, core_id, thread_id); + } + } else { + if (xscom_write(chip_id, dctl_addr, P9_THREAD_CONT(thread_id))) { + prlog(PR_ERR, "Could not resume thread %u:%u:%u:" + " Unable to write EC_DIRECT_CONTROLS.\n", + chip_id, core_id, thread_id); + } + } + + return 0; +} + static int p9_stop_thread(struct cpu_thread *cpu) { uint32_t chip_id = pir_to_chip_id(cpu->pir); @@ -461,23 +531,6 @@ static int p9_stop_thread(struct cpu_thread *cpu) return OPAL_HARDWARE; } -static int p9_cont_thread(struct cpu_thread *cpu) -{ - uint32_t chip_id = pir_to_chip_id(cpu->pir); - uint32_t core_id = pir_to_core_id(cpu->pir); - uint32_t thread_id = pir_to_thread_id(cpu->pir); - uint32_t dctl_addr; - - dctl_addr = XSCOM_ADDR_P9_EC(core_id, P9_EC_DIRECT_CONTROLS); - if (xscom_write(chip_id, dctl_addr, P9_THREAD_CONT(thread_id))) { - prlog(PR_ERR, "Could not resume thread %u:%u:%u:" - " Unable to write EC_DIRECT_CONTROLS.\n", - chip_id, core_id, thread_id); - } - - return 0; -} - static int p9_sreset_thread(struct cpu_thread *cpu) { uint32_t chip_id = pir_to_chip_id(cpu->pir); |